Skip to content

Commit d01ee0a

Browse files
committed
Rewrite README around usage
State that Gmail is the only supported API, install the package and its peers from npm, and add a quickstart, a tool reference with approval gates, the sidecar-bundle and interchange manifest entries, and an authenticated fetchImpl for createGmailClient. Development and live Gmail checks move to CONTRIBUTING.md.
1 parent e2e9828 commit d01ee0a

2 files changed

Lines changed: 118 additions & 41 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Contributing
2+
3+
## Development
4+
5+
```bash
6+
bun install
7+
bun run typecheck
8+
bun run typecheck:live
9+
bun run test
10+
bun run build
11+
```
12+
13+
The tests inject `fetch` implementations and do not call Gmail.
14+
15+
## Live Gmail checks
16+
17+
Use a dedicated Gmail fixture account and a Desktop OAuth client granted only
18+
`gmail.modify`. The read smoke requires a query that matches exactly one
19+
one-message thread:
20+
21+
```bash
22+
GMAIL_LIVE_TEST=1 \
23+
GMAIL_LIVE_CLIENT_ID='...' \
24+
GMAIL_LIVE_CLIENT_SECRET='...' \
25+
GMAIL_LIVE_FIXTURE_QUERY='subject:(interchange-gmail-e2e-fixture)' \
26+
bun run test:live
27+
```
28+
29+
The full live suite has been verified against a dedicated Gmail fixture account.
30+
It exercises every Gmail tool:
31+
32+
- `gmail_search_threads` finds the one-message fixture thread.
33+
- `gmail_get_thread` and `gmail_get_message` retrieve its metadata.
34+
- `gmail_list_labels` lists the account labels.
35+
- `gmail_create_draft` and `gmail_list_drafts` create and find a disposable
36+
draft, which the suite then deletes.
37+
- `gmail_label_message` and `gmail_unlabel_message` add and remove `STARRED`
38+
on the fixture message.
39+
- `gmail_label_thread` and `gmail_unlabel_thread` add and remove `STARRED`
40+
on every message in the fixture thread.
41+
42+
Add `GMAIL_LIVE_MUTATION_TEST=1` to run the draft and label checks. The suite
43+
deletes its draft, restores the fixture labels, and never sends email.
44+
45+
The first run opens Google OAuth and stores the refresh token in the ignored
46+
`.local/gmail-live-token.json` file. Set `GMAIL_LIVE_TOKEN_FILE` when using a
47+
different token file. Credentials and message contents are not logged.

‎README.md‎

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,94 @@
11
# @corbits/google-tools
22

3-
Google API clients and Interchange tools, starting with Gmail. Authentication
4-
is supplied through the Interchange `gmail-api` mediated credential; the
5-
package never accepts or returns raw tokens.
3+
Gmail tools for AI agents: search, read, label and draft over the Gmail REST API, authenticated by an HTTP credential that signs each request so the agent never holds an OAuth token. A tool pack for the Interchange sidecar that also runs standalone.
64

7-
## Requirements
5+
## Why @corbits/google-tools?
86

9-
Node.js 24 or newer (`engines.node >=24`).
7+
1. **No tokens in the agent.** Tools call Gmail through a credential the host resolves at run time. The OAuth token never enters the model context or tool arguments.
8+
2. **Human approval on every write.** Label changes and draft creation use `approval: "ask"`, so Interchange pauses each call until a person approves it. No tool can send mail.
9+
3. **Grant-gated in Interchange.** The package declares the `gmail-api` credential and the `gmail.modify` scope it needs. The hub (Interchange's control plane) stores the credential, and a grant (a record of which agent may use it) decides which agents get it.
10+
11+
It covers Gmail only, not other Google APIs.
1012

1113
## Install
1214

1315
```bash
14-
bun add github:corbitsdev/google-tools
16+
bun add @corbits/google-tools @intx/agent @intx/types
1517
```
1618

17-
## Working on it
19+
Requires Node.js 24 or newer.
1820

19-
```bash
20-
bun install
21-
bun run typecheck
22-
bun test
23-
bun run build
24-
```
21+
## Quickstart
2522

26-
The tests inject `fetch` implementations and do not call Gmail.
23+
Lists your mailbox labels. Needs a Gmail OAuth access token with the
24+
`https://www.googleapis.com/auth/gmail.modify` scope in `GMAIL_ACCESS_TOKEN`.
2725

28-
## Live Gmail checks
26+
```ts
27+
import { createGmailClient } from "@corbits/google-tools";
2928

30-
Use a dedicated Gmail fixture account and a Desktop OAuth client granted only
31-
`gmail.modify`. The read smoke requires a query that matches exactly one
32-
one-message thread:
29+
const gmail = createGmailClient({
30+
fetchImpl: (url, init) => {
31+
const request = new Request(url, init);
32+
request.headers.set("Authorization", `Bearer ${process.env.GMAIL_ACCESS_TOKEN}`);
33+
return fetch(request);
34+
},
35+
});
3336

34-
```bash
35-
GMAIL_LIVE_TEST=1 \
36-
GMAIL_LIVE_CLIENT_ID='...' \
37-
GMAIL_LIVE_CLIENT_SECRET='...' \
38-
GMAIL_LIVE_FIXTURE_QUERY='subject:(interchange-gmail-e2e-fixture)' \
39-
bun run test:live
37+
console.log(await gmail.listLabels());
4038
```
4139

42-
The full live suite has been verified against a dedicated Gmail fixture account.
43-
It exercises every Gmail tool:
40+
## Where it fits
41+
42+
[Interchange](https://github.com/faremeter/interchange) runs AI agents as principals (accounts that hold their own identity, permissions and credentials).
43+
44+
- Runs in the sidecar, the runtime that hosts each agent and its tools.
45+
- Registers its tools with `defineTool` from
46+
[`@intx/agent`](https://github.com/faremeter/interchange/tree/main/packages/agent).
47+
- Reads the Gmail credential from the runtime capabilities in
48+
[`@intx/types`](https://github.com/faremeter/interchange/tree/main/packages/types).
49+
- Pairs with
50+
[`@corbits/oauth-core`](https://github.com/corbitsdev/corbits-oauth-core),
51+
which obtains the Google credential the hub stores.
52+
53+
## Tools
54+
55+
| Tool | Purpose | Approval |
56+
| ----------------------- | --------------------------------------------------- | -------- |
57+
| `gmail_search_threads` | Search the mailbox and return thread summaries. | No |
58+
| `gmail_get_thread` | Fetch one thread with selected message detail. | No |
59+
| `gmail_get_message` | Fetch one message with selected detail. | No |
60+
| `gmail_list_labels` | List the mailbox labels. | No |
61+
| `gmail_create_draft` | Create a draft, optionally as a reply. Never sends. | Yes |
62+
| `gmail_list_drafts` | List drafts with Gmail-query filtering. | No |
63+
| `gmail_label_message` | Add labels to a message. | Yes |
64+
| `gmail_unlabel_message` | Remove labels from a message. | Yes |
65+
| `gmail_label_thread` | Add labels to every message in a thread. | Yes |
66+
| `gmail_unlabel_thread` | Remove labels from every message in a thread. | Yes |
67+
68+
Tools marked Yes use `approval: "ask"`. Interchange pauses each call until a
69+
person approves it.
70+
71+
## Using with Interchange
72+
73+
The sidecar loads tools from the `./sidecar-bundle` export. It exports `gmail`,
74+
which builds the tools from the `capabilities` in the agent's environment:
75+
76+
```ts
77+
import { gmail } from "@corbits/google-tools/sidecar-bundle";
78+
```
4479

45-
- `gmail_search_threads` finds the one-message fixture thread.
46-
- `gmail_get_thread` and `gmail_get_message` retrieve its metadata.
47-
- `gmail_list_labels` lists the account labels.
48-
- `gmail_create_draft` and `gmail_list_drafts` create and find a disposable
49-
draft, which the suite then deletes.
50-
- `gmail_label_message` and `gmail_unlabel_message` add and remove `STARRED`
51-
on the fixture message.
52-
- `gmail_label_thread` and `gmail_unlabel_thread` add and remove `STARRED`
53-
on every message in the fixture thread.
80+
The package's `package.json` tells Interchange what to load:
5481

55-
Add `GMAIL_LIVE_MUTATION_TEST=1` to run the draft and label checks. The suite
56-
deletes its draft, restores the fixture labels, and never sends email.
82+
- `interchange.tools` points at `./dist/sidecar-bundle.js`.
83+
- `interchange.credentials` asks for a credential named `gmail-api` with the
84+
`https://www.googleapis.com/auth/gmail.modify` scope.
5785

58-
The first run opens Google OAuth and stores the refresh token in the ignored
59-
`.local/gmail-live-token.json` file. Set `GMAIL_LIVE_TOKEN_FILE` when using a
60-
different token file. Credentials and message contents are not logged.
86+
To connect it, store the user's Google OAuth credential on the hub as
87+
`gmail-api` and grant it to the agent. The sidecar resolves it for the tools at
88+
run time.
6189

6290
## License
6391

64-
LGPL-2.1-only. See [LICENSE](./LICENSE).
92+
LGPL-2.1-only. See
93+
[LICENSE](https://github.com/corbitsdev/google-tools/blob/main/LICENSE).
94+
Development notes are in [CONTRIBUTING.md](https://github.com/corbitsdev/google-tools/blob/main/CONTRIBUTING.md).

0 commit comments

Comments
 (0)