@mappies/miniwat-agent 0.5.0 → 0.8.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/README.md CHANGED
@@ -1 +1,914 @@
1
- # miniwat-agent
1
+ # Miniwat Agent
2
+
3
+ > Build conversational AI applications with OpenAI or AWS Bedrock in
4
+ > just a few lines of code.
5
+
6
+ The `Agent` class is the main entry point to miniwat. It combines a
7
+ language model, optional system instructions, an optional planner, conversation history, and
8
+ streaming into a simple API.
9
+
10
+ ``` ts
11
+ const model = new OpenAiModel({
12
+ modelId: "gpt-4.1-mini",
13
+ apiKey: process.env.OPENAI_API_KEY
14
+ });
15
+
16
+ const agent = new Agent({ model });
17
+ const session = new Session();
18
+
19
+ const response = await agent.invoke("Hello!", session);
20
+
21
+ console.log(response.message.content);
22
+ ```
23
+
24
+ ------------------------------------------------------------------------
25
+
26
+ # Why miniwat?
27
+
28
+ Most LLM libraries require you to manually:
29
+
30
+ - Track conversation history
31
+ - Send the entire message list every request
32
+ - Configure streaming
33
+ - Manage model-specific APIs
34
+
35
+ With miniwat you work with only three objects:
36
+
37
+ ``` text
38
+ Model
39
+
40
+ Agent
41
+
42
+ Session
43
+ ```
44
+
45
+ Everything else happens automatically.
46
+
47
+ ------------------------------------------------------------------------
48
+
49
+ # Installation
50
+
51
+ ``` bash
52
+ npm install @mappies/miniwat-agent
53
+ ```
54
+
55
+ Choose one model implementation.
56
+
57
+ ``` bash
58
+ npm install @mappies/miniwat-provider-openai
59
+ ```
60
+
61
+ or
62
+
63
+ ``` bash
64
+ npm install @mappies/miniwat-provider-bedrock
65
+ ```
66
+
67
+ ------------------------------------------------------------------------
68
+
69
+ # Quick Start
70
+
71
+ The following example creates an AI assistant using OpenAI. It can be copied directly into a project and run as-is.
72
+
73
+ ```ts
74
+ import { Agent, Session } from "@mappies/miniwat-agent";
75
+ import { OpenAiModel } from "@mappies/miniwat-provider-openai";
76
+
77
+ async function main() {
78
+ const model = new OpenAiModel({
79
+ modelId: "gpt-4.1-mini",
80
+ apiKey: process.env.OPENAI_API_KEY
81
+ });
82
+
83
+ const agent = new Agent({
84
+ model,
85
+ instruction: {
86
+ system: {
87
+ value: "You are a helpful assistant."
88
+ }
89
+ }
90
+ });
91
+
92
+ const session = new Session();
93
+
94
+ const response = await agent.invoke(
95
+ "Explain what TypeScript is in one paragraph.",
96
+ session
97
+ );
98
+
99
+ console.log(response.message.content);
100
+ }
101
+
102
+ main().catch(console.error);
103
+ ```
104
+
105
+ Run the example after setting your OpenAI API key.
106
+
107
+ **Linux / macOS**
108
+
109
+ ```bash
110
+ export OPENAI_API_KEY=your_api_key
111
+ node app.js
112
+ ```
113
+
114
+ **Windows PowerShell**
115
+
116
+ ```powershell
117
+ $env:OPENAI_API_KEY="your_api_key"
118
+ node app.js
119
+ ```
120
+
121
+ Congratulations! You've built your first miniwat application.
122
+
123
+ The rest of this guide explains each part of the example in more detail.
124
+
125
+ ------------------------------------------------------------------------
126
+
127
+ # Your First Agent
128
+
129
+ ## Step 1 --- Create a model
130
+
131
+ ### OpenAI
132
+
133
+ ``` ts
134
+ import { OpenAiModel } from "@mappies/miniwat-provider-openai";
135
+
136
+ const model = new OpenAiModel({
137
+ modelId: "gpt-4.1-mini",
138
+ apiKey: process.env.OPENAI_API_KEY
139
+ });
140
+ ```
141
+
142
+ ### AWS Bedrock
143
+
144
+ ``` ts
145
+ import { BedrockModel } from "@mappies/miniwat-provider-bedrock";
146
+
147
+ const model = new BedrockModel({
148
+ region: "us-east-1",
149
+ modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0"
150
+ });
151
+ ```
152
+
153
+ ------------------------------------------------------------------------
154
+
155
+ ## Step 2 --- Create an Agent
156
+
157
+ ``` ts
158
+ const agent = new Agent({
159
+ model
160
+ });
161
+ ```
162
+
163
+ At this point the agent is ready to answer prompts.
164
+
165
+ Planning is optional. When no planner is configured, the agent sends prompts directly to the model. To enable multi-step planning, provide a planner when creating the agent.
166
+
167
+ ``` ts
168
+ import { DefaultPlanner } from "@mappies/miniwat-agent";
169
+
170
+ const planner = new DefaultPlanner(model);
171
+
172
+ const agent = new Agent({
173
+ model,
174
+ planner
175
+ });
176
+ ```
177
+
178
+ ------------------------------------------------------------------------
179
+
180
+ ## Step 3 --- Create a Session
181
+
182
+ ``` ts
183
+ const session = new Session();
184
+ ```
185
+
186
+ A `Session` stores the conversation history.
187
+
188
+ Think of it as a chat thread.
189
+
190
+ Reuse the same session if you want the model to remember previous
191
+ messages.
192
+
193
+ ------------------------------------------------------------------------
194
+
195
+ ## Step 4 --- Ask a question
196
+
197
+ ``` ts
198
+ const response = await agent.invoke(
199
+ "Explain TypeScript generics.",
200
+ session
201
+ );
202
+
203
+ console.log(response.message.content);
204
+ ```
205
+
206
+ That's all you need to build a basic chatbot.
207
+
208
+ ------------------------------------------------------------------------
209
+
210
+ # Conversation Memory
211
+
212
+ Every call automatically appends:
213
+
214
+ 1. your prompt
215
+ 2. the assistant response
216
+
217
+ to the session.
218
+
219
+ ``` ts
220
+ await agent.invoke("My name is Alice.", session);
221
+
222
+ await agent.invoke(
223
+ "What's my name?",
224
+ session
225
+ );
226
+ ```
227
+
228
+ Because both requests share the same session, the model remembers the
229
+ earlier conversation.
230
+
231
+ To start over:
232
+
233
+ ``` ts
234
+ const newSession = new Session();
235
+ ```
236
+
237
+ ------------------------------------------------------------------------
238
+
239
+ # Customizing the Assistant
240
+
241
+ Add a system instruction.
242
+
243
+ ``` ts
244
+ const agent = new Agent({
245
+ model,
246
+ instruction: {
247
+ system: {
248
+ value: "You are a friendly programming tutor."
249
+ }
250
+ }
251
+ });
252
+ ```
253
+
254
+ This instruction is applied automatically to every request.
255
+
256
+ ------------------------------------------------------------------------
257
+
258
+ # Streaming Responses
259
+
260
+ For chat applications, streaming provides a better user experience.
261
+
262
+ ``` ts
263
+ const stream = await agent.stream(
264
+ "Write a short story.",
265
+ session
266
+ );
267
+
268
+ stream.on("data", chunk => {
269
+ process.stdout.write(chunk);
270
+ });
271
+
272
+ await (stream as any).promise;
273
+ ```
274
+
275
+ The stream promise ensures the completed response is written back into
276
+ the session.
277
+
278
+ ------------------------------------------------------------------------
279
+
280
+ # Model Options
281
+
282
+ Pass inference settings per request.
283
+
284
+ ``` ts
285
+ await agent.invoke(prompt, session, {
286
+ inference: {
287
+ temperature: 0.2,
288
+ maxTokens: 800,
289
+ topP: 0.9
290
+ }
291
+ });
292
+ ```
293
+
294
+ A temperature of **0.2** is recommended for most assistants.
295
+
296
+ ------------------------------------------------------------------------
297
+
298
+ # Events
299
+
300
+ Applications often need progress updates.
301
+
302
+ ``` ts
303
+ await agent.invoke(prompt, session, {
304
+ event: {
305
+ onThinking: async text => {
306
+ console.log(text);
307
+ },
308
+
309
+ onTooling: async message => {
310
+ console.log(message);
311
+ },
312
+
313
+ onResponse: async message => {
314
+ console.log(message.content);
315
+ },
316
+
317
+ onPlanUpdated: async plan => {
318
+ console.log(plan);
319
+ }
320
+ }
321
+ });
322
+ ```
323
+
324
+ `onPlanUpdated` is called when a configured planner's plan changes during execution.
325
+
326
+ Typical uses include:
327
+
328
+ - updating a status indicator
329
+ - logging tool execution
330
+ - displaying plan execution progress
331
+ - saving completed responses
332
+
333
+ ------------------------------------------------------------------------
334
+
335
+ # Building a Chat Loop
336
+
337
+ ``` ts
338
+ while (true) {
339
+ const response = await agent.invoke(userInput, session);
340
+
341
+ console.log(response.message.content);
342
+ }
343
+ ```
344
+
345
+ Notice there is no manual message management.
346
+
347
+ The session grows automatically.
348
+
349
+ ------------------------------------------------------------------------
350
+
351
+ # Using MCP Tools
352
+
353
+ One of miniwat's primary design goals is to make AI agents **safe to use in production**.
354
+
355
+ Unlike many agent frameworks that allow language models to connect to arbitrary MCP servers, **miniwat takes a security-first approach**. Only **miniwat-approved MCP packages** can be used by an application. MCP packages are **not** downloaded or installed automatically—they must be explicitly installed with `npm` before they can be configured and used.
356
+
357
+ This explicit opt-in model helps reduce risks such as:
358
+
359
+ - Executing untrusted code
360
+ - Loading unexpected third-party MCP servers
361
+ - Accessing unauthorized local or network resources
362
+ - Accidentally exposing secrets
363
+ - Server-Side Request Forgery (SSRF)
364
+ - Prompt injection through unsafe tools
365
+ - Data exfiltration
366
+
367
+ The philosophy is simple:
368
+
369
+ > **Powerful AI agents require trustworthy tools.**
370
+
371
+ By requiring applications to explicitly install and configure approved MCP packages, miniwat gives developers complete control over the capabilities exposed to their agents while maintaining a strong security posture.
372
+
373
+ ## Serverless MCP Architecture
374
+
375
+ miniwat is also designed around a **serverless MCP architecture**.
376
+
377
+ Rather than communicating with long-running MCP servers over stdio, HTTP, or WebSockets, miniwat executes **functions exported by locally installed npm packages**. This eliminates the need to deploy, monitor, and secure separate MCP server processes, making miniwat a natural fit for modern serverless platforms.
378
+
379
+ This design provides several advantages:
380
+
381
+ - **Lower latency** – Tool functions execute directly within your application process.
382
+ - **Simpler deployment** – No MCP servers need to be started or managed.
383
+ - **Reduced operational overhead** – Deploy a single application instead of multiple services.
384
+ - **Improved security** – Only explicitly installed and approved MCP packages can be executed.
385
+ - **Serverless friendly** – Works naturally in environments such as AWS Lambda, Azure Functions, and Google Cloud Functions, where long-running MCP servers are impractical.
386
+
387
+ Because miniwat executes functions instead of connecting to external MCP servers, it uses its own `mcp.json` format. Rather than describing how to connect to remote servers, the configuration describes:
388
+
389
+ - which npm package provides the MCP implementation
390
+ - which tool definitions from that package are exposed to the language model
391
+ - which environment variables are required as secrets
392
+
393
+ This approach keeps MCP configuration simple while making deployments portable, secure, and well suited for serverless applications.
394
+
395
+ ---
396
+
397
+ ## Available MCP Servers
398
+
399
+ The following MCP servers are currently approved for use with miniwat.
400
+
401
+ | MCP | npm Package | Description | Repository |
402
+ |-----|-------------|-------------|------------|
403
+ | **Weather** | `@mappies/miniwat-mcp-weather` | Provides weather tools, including current weather and daily forecast lookup. | `https://gitlab.com/mappies/miniwat/mcp/weather` |
404
+ | **Web** | `@mappies/miniwat-mcp-web` | Provides web tools, including web search and safe URL fetching. | `https://gitlab.com/mappies/miniwat/mcp/web` |
405
+ | **Trello** | `@mappies/miniwat-mcp-trello` | Provides Trello tools for boards, lists, cards, labels, members, and workspaces. | `https://gitlab.com/mappies/miniwat/mcp/trello` |
406
+
407
+ > **Important**
408
+ >
409
+ > miniwat does not download MCP packages automatically. You must install the MCP packages yourself.
410
+
411
+ ```bash
412
+ npm install @mappies/miniwat-mcp-weather
413
+ npm install @mappies/miniwat-mcp-web
414
+ npm install @mappies/miniwat-mcp-trello
415
+ ```
416
+
417
+ ---
418
+
419
+ ## miniwat MCP Config Format
420
+
421
+ miniwat uses its own MCP configuration format.
422
+
423
+ It does **not** use the standard MCP `mcp.json` format.
424
+
425
+ A miniwat MCP config uses a top-level `mcpServers` object. Each MCP server entry defines:
426
+
427
+ - the npm package that provides the MCP implementation
428
+ - the tool definitions to expose to the language model
429
+ - optional `secrets` required by that MCP
430
+
431
+ Each MCP package may provide many tool definitions. The `tools` array allows you to explicitly choose which tool definitions are exposed to your agent. This follows the principle of least privilege—only the capabilities your application requires are made available to the language model.
432
+
433
+ For example, the Weather MCP provides both current weather and weather forecast tools. If your application only needs current weather, simply omit the forecast tool from the configuration.
434
+
435
+ Example `mcp.json`:
436
+
437
+ ```json
438
+ {
439
+ "mcpServers": {
440
+ "Weather": {
441
+ "package": "@mappies/miniwat-mcp-weather",
442
+ "tools": [
443
+ {
444
+ "import": "GET_CURRENT_WEATHER_DEFINITION"
445
+ },
446
+ {
447
+ "import": "GET_WEATHER_FORECAST_DEFINITION"
448
+ }
449
+ ]
450
+ },
451
+ "Web": {
452
+ "package": "@mappies/miniwat-mcp-web",
453
+ "tools": [
454
+ {
455
+ "import": "SEARCH_WEB_DEFINITION"
456
+ },
457
+ {
458
+ "import": "FETCH_URL_DEFINITION"
459
+ }
460
+ ]
461
+ },
462
+ "Trello": {
463
+ "package": "@mappies/miniwat-mcp-trello",
464
+ "secrets": [
465
+ "TRELLO_API_KEY",
466
+ "TRELLO_TOKEN"
467
+ ],
468
+ "tools": [
469
+ {
470
+ "import": "LIST_TRELLO_BOARDS_DEFINITION"
471
+ },
472
+ {
473
+ "import": "CREATE_TRELLO_BOARD_DEFINITION"
474
+ },
475
+ {
476
+ "import": "GET_TRELLO_BOARD_DEFINITION"
477
+ },
478
+ {
479
+ "import": "LIST_TRELLO_LISTS_DEFINITION"
480
+ },
481
+ {
482
+ "import": "MOVE_TRELLO_LIST_DEFINITION"
483
+ },
484
+ {
485
+ "import": "GET_TRELLO_CARD_DEFINITION"
486
+ },
487
+ {
488
+ "import": "LIST_TRELLO_LABELS_DEFINITION"
489
+ },
490
+ {
491
+ "import": "UPDATE_CARD_TITLE_DEFINITION"
492
+ },
493
+ {
494
+ "import": "REMOVE_CARD_LABEL_DEFINITION"
495
+ },
496
+ {
497
+ "import": "ADD_CARD_LABEL_DEFINITION"
498
+ },
499
+ {
500
+ "import": "ADD_MEMBER_TO_BOARD_DEFINITION"
501
+ },
502
+ {
503
+ "import": "LIST_TRELLO_CARDS_DEFINITION"
504
+ },
505
+ {
506
+ "import": "LIST_TRELLO_WORKSPACES_DEFINITION"
507
+ }
508
+ ]
509
+ }
510
+ }
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Configuring a Model with MCP Tools
517
+
518
+ In miniwat, MCP tools are passed to the model through the `mcpConfig` option.
519
+
520
+ For example, import your `mcp.json` file:
521
+
522
+ ```ts
523
+ import mcpConfig from "./mcp.json";
524
+ ```
525
+
526
+ Then pass it to the model provider.
527
+
528
+ ### OpenAI
529
+
530
+ ```ts
531
+ import { OpenAiModel } from "@mappies/miniwat-provider-openai";
532
+ import mcpConfig from "./mcp.json";
533
+
534
+ const model = new OpenAiModel({
535
+ modelId: "gpt-4.1-mini",
536
+ apiKey: process.env.OPENAI_API_KEY,
537
+ mcpConfig
538
+ });
539
+ ```
540
+
541
+ ### AWS Bedrock
542
+
543
+ ```ts
544
+ import { BedrockModel } from "@mappies/miniwat-provider-bedrock";
545
+ import mcpConfig from "./mcp.json";
546
+
547
+ const model = new BedrockModel({
548
+ region: "us-east-1",
549
+ modelId: "your-bedrock-model-id-or-arn",
550
+ mcpConfig
551
+ });
552
+ ```
553
+
554
+ The provider creates a `ToolDispatcher` internally from the given `mcpConfig`.
555
+
556
+ ---
557
+
558
+ ## Using MCP Tools with Agent
559
+
560
+ After the model is configured with `mcpConfig`, create an `Agent` normally.
561
+
562
+ ```ts
563
+ import { Agent, Session } from "@mappies/miniwat-agent";
564
+
565
+ const agent = new Agent({
566
+ model,
567
+ instruction: {
568
+ system: {
569
+ value: "You are a helpful assistant."
570
+ }
571
+ }
572
+ });
573
+
574
+ const session = new Session();
575
+
576
+ const response = await agent.invoke(
577
+ "What's the weather in Blacksburg tomorrow?",
578
+ session
579
+ );
580
+
581
+ console.log(response.message.content);
582
+ ```
583
+
584
+ The model can now discover the configured miniwat-approved tools and call them when needed.
585
+
586
+ ---
587
+
588
+ ## Passing Secrets to MCP Servers
589
+
590
+ Some MCP servers require credentials.
591
+
592
+ For example, the Trello MCP requires:
593
+
594
+ ```json
595
+ "secrets": [
596
+ "TRELLO_API_KEY",
597
+ "TRELLO_TOKEN"
598
+ ]
599
+ ```
600
+
601
+ The `secrets` array tells miniwat which environment variables are required by that MCP server.
602
+
603
+ Do **not** put secret values directly inside `mcp.json`.
604
+
605
+ Instead, define them as environment variables before starting your application.
606
+
607
+ ### Linux / macOS
608
+
609
+ ```bash
610
+ export TRELLO_API_KEY=your_trello_api_key
611
+ export TRELLO_TOKEN=your_trello_token
612
+ ```
613
+
614
+ ### Windows PowerShell
615
+
616
+ ```powershell
617
+ $env:TRELLO_API_KEY="your_trello_api_key"
618
+ $env:TRELLO_TOKEN="your_trello_token"
619
+ ```
620
+
621
+ Your `mcp.json` should only contain the names of the required secrets:
622
+
623
+ ```json
624
+ {
625
+ "mcpServers": {
626
+ "Trello": {
627
+ "package": "@mappies/miniwat-mcp-trello",
628
+ "secrets": [
629
+ "TRELLO_API_KEY",
630
+ "TRELLO_TOKEN"
631
+ ],
632
+ "tools": [
633
+ {
634
+ "import": "LIST_TRELLO_BOARDS_DEFINITION"
635
+ }
636
+ ]
637
+ }
638
+ }
639
+ }
640
+ ```
641
+
642
+ This keeps sensitive values out of source control.
643
+
644
+ ---
645
+
646
+ ## Building a Custom MCP Package
647
+
648
+ A miniwat MCP is simply an **npm package** that exports tool definitions and their corresponding implementation functions.
649
+
650
+ Unlike traditional MCP implementations, there is no server to run. miniwat loads your package directly and executes the exported functions.
651
+
652
+ ### Package Structure
653
+
654
+ A simple MCP package might look like this:
655
+
656
+ ```text
657
+ my-mcp/
658
+ ├── package.json
659
+ └── src/
660
+ ├── index.ts
661
+ └── getRandomNumber.ts
662
+ ```
663
+
664
+ ### Export a Tool Definition
665
+
666
+ Every tool begins with a definition that describes the tool to the language model.
667
+
668
+ ```ts
669
+ export const GET_RANDOM_NUMBER_DEFINITION = {
670
+ name: "getRandomNumber",
671
+ description: "Generate a random number between two values.",
672
+ inputSchema: {
673
+ type: "object",
674
+ properties: {
675
+ min: { type: "number" },
676
+ max: { type: "number" }
677
+ },
678
+ required: ["min", "max"]
679
+ }
680
+ } as const;
681
+ ```
682
+
683
+ ### Export the Tool Function
684
+
685
+ Each tool definition must have a corresponding exported function whose name exactly matches the definition's `name` property.
686
+
687
+ The function accepts a **single object parameter**, with properties that match the tool's `inputSchema`. When the language model invokes the tool, miniwat automatically maps the generated JSON arguments to this object and calls your function.
688
+
689
+
690
+ ```ts
691
+ export async function getRandomNumber({ min, max }: { min: number; max: number; }) {
692
+ return {
693
+ value: Math.floor(Math.random() * (max - min + 1)) + min
694
+ };
695
+ }
696
+ ```
697
+
698
+ ### Optional: Input Text Helper
699
+
700
+ If you want the UI to display status updates while the tool is running, export an input text helper.
701
+
702
+ ```ts
703
+ export function getRandomNumberInputText({ min, max }: { min: number; max: number; }) {
704
+ return `Generating a random number between ${min} and ${max}.`;
705
+ }
706
+ ```
707
+
708
+ ### Export Everything
709
+
710
+ Export the definitions and functions from your package.
711
+
712
+ ```ts
713
+ export * from "./getRandomNumber";
714
+ ```
715
+
716
+ ### Use the Package
717
+
718
+ Install the package into your application.
719
+
720
+ ```bash
721
+ npm install @your-org/my-mcp
722
+ ```
723
+
724
+ Then expose the desired tool definitions in `mcp.json`.
725
+
726
+ ```json
727
+ {
728
+ "mcpServers": {
729
+ "Example": {
730
+ "package": "@your-org/my-mcp",
731
+ "tools": [
732
+ {
733
+ "import": "GET_RANDOM_NUMBER_DEFINITION"
734
+ }
735
+ ]
736
+ }
737
+ }
738
+ }
739
+ ```
740
+
741
+ Only the tool definitions listed in `mcp.json` are exposed to the language model, allowing you to choose exactly which actions your agent can perform.
742
+
743
+ ---
744
+
745
+ ## Example: Model Provider Factory
746
+
747
+ A common pattern is to create a model factory that always loads the MCP config.
748
+
749
+ ```ts
750
+ import { Model } from "@mappies/miniwat-agent-core";
751
+ import { BedrockModel } from "@mappies/miniwat-provider-bedrock";
752
+ import { OpenAiModel } from "@mappies/miniwat-provider-openai";
753
+ import mcpConfig from "../mcp.json";
754
+
755
+ export class ModelProviderFactory {
756
+ static create(): Model {
757
+ const options = {
758
+ mcpConfig
759
+ };
760
+
761
+ if (process.env.OPENAI_API_KEY) {
762
+ return new OpenAiModel({
763
+ ...options,
764
+ modelId: process.env.DEFAULT_OPENAI_MODEL || "gpt-4.1-mini",
765
+ apiKey: process.env.OPENAI_API_KEY,
766
+ baseURL: process.env.OPENAI_BASE_URL
767
+ });
768
+ }
769
+
770
+ return new BedrockModel({
771
+ ...options,
772
+ region: process.env.AWS_REGION,
773
+ modelId: process.env.DEFAULT_BEDROCK_MODEL_ARN || ""
774
+ });
775
+ }
776
+ }
777
+ ```
778
+
779
+ Then use the factory when creating your agent.
780
+
781
+ ```ts
782
+ const model = ModelProviderFactory.create();
783
+
784
+ const agent = new Agent({
785
+ model,
786
+ instruction: {
787
+ system: {
788
+ value: "You are a helpful assistant."
789
+ }
790
+ }
791
+ });
792
+ ```
793
+
794
+ ---
795
+
796
+ ## Automatic Tool Execution
797
+
798
+ Once the model is configured with `mcpConfig`, tool execution is automatic.
799
+
800
+ For example, if the user asks:
801
+
802
+ > What's the weather in Blacksburg tomorrow?
803
+
804
+ The model may invoke the **Weather** MCP.
805
+
806
+ If the user asks:
807
+
808
+ > Search the web for the latest TypeScript release notes.
809
+
810
+ The model may invoke the **Web** MCP.
811
+
812
+ If the user asks:
813
+
814
+ > Summarize https://example.com/report.pdf
815
+
816
+ The model may invoke the **Web** MCP's `fetchUrl` tool.
817
+
818
+ If the user asks:
819
+
820
+ > Create a Trello board named Sprint Planning.
821
+
822
+ The model may invoke the **Trello** MCP.
823
+
824
+ From your application's perspective, there is nothing special to do.
825
+
826
+ ```ts
827
+ const response = await agent.invoke(prompt, session);
828
+ ```
829
+
830
+ The model provider and `ToolDispatcher` handle the tool workflow:
831
+
832
+ 1. List configured tools from `mcpConfig`.
833
+ 2. Send tool definitions to the model.
834
+ 3. Let the model choose a tool when needed.
835
+ 4. Execute the selected tool.
836
+ 5. Send the tool result back to the model.
837
+ 6. Continue the conversation.
838
+ 7. Return the final response.
839
+
840
+ ---
841
+
842
+ ## Observing Tool Activity
843
+
844
+ You can observe tool activity with `onTooling`.
845
+
846
+ ```ts
847
+ const response = await agent.invoke(prompt, session, {
848
+ event: {
849
+ onThinking: async text => {
850
+ console.log("Thinking:", text);
851
+ },
852
+ onTooling: async message => {
853
+ console.log("Tool activity:", message);
854
+ },
855
+ onResponse: async message => {
856
+ console.log("Response:", message.content);
857
+ }
858
+ }
859
+ });
860
+ ```
861
+
862
+ This is useful for:
863
+
864
+ - logging tool calls
865
+ - displaying status updates in a UI
866
+ - saving tool call history
867
+ - debugging MCP behavior
868
+
869
+ ------------------------------------------------------------------------
870
+
871
+ # Which API should I use?
872
+
873
+ ## invoke()
874
+
875
+ Use when you want the complete response.
876
+
877
+ ``` ts
878
+ await agent.invoke(prompt, session);
879
+ ```
880
+
881
+ ## stream()
882
+
883
+ Use when building chat interfaces.
884
+
885
+ ``` ts
886
+ await agent.stream(prompt, session);
887
+ ```
888
+
889
+ ------------------------------------------------------------------------
890
+
891
+ # Best Practices
892
+
893
+ - Create one `Session` per conversation.
894
+ - Reuse that session until the conversation ends.
895
+ - Use `stream()` for interactive UIs.
896
+ - Keep system instructions short and focused.
897
+ - Use low temperatures for factual assistants.
898
+
899
+ ------------------------------------------------------------------------
900
+
901
+ # Next Steps
902
+
903
+ You now know how to:
904
+
905
+ - create a model
906
+ - create an agent
907
+ - maintain conversations with sessions
908
+ - customize behavior with instructions
909
+ - stream responses
910
+ - receive events
911
+ - build a chatbot
912
+
913
+ From here you can integrate miniwat into a CLI, web server, desktop
914
+ application, or WebSocket chat service.