bots-garden/mini-mepublic Fork
⑂ v1.0.8
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. bfca5aa · on v1.0.8 · k33g · 3d ago
offer-tools-from-an-acp-client.md · 115 lines · 5.3 KBmarkdown
Blame HistoryOpen raw

Proposer des outils depuis votre client ACP

Ce guide montre comment un programme Go qui pilote mm -acp donne à l'agent ses propres outils : des fonctions de votre programme que le modèle appelle comme ses outils intégrés (les buffers ouverts d'un éditeur, les données d'une application, une liste de tâches…). Il suppose que votre programme est déjà un client ACP de mm, écrit avec github.com/coder/acp-go-sdk (v0.13.5, la version qu'utilise mm). Le protocole exact est dans la spécification des outils du client.

Étapes

1. Décrire vos outils

Une description par outil : un nom, une description pour le modèle, la méthode d'extension que mm appellera (elle doit commencer par _), et le schéma JSON des arguments.

type toolSpec struct {
	Name        string         `json:"name"`
	Description string         `json:"description,omitempty"`
	Method      string         `json:"method"`
	InputSchema map[string]any `json:"inputSchema,omitempty"`
}

var tools = []toolSpec{{
	Name:        "add_todo",
	Description: "Add one item to the user's to-do list.",
	Method:      "_com.example/todo/add",
	InputSchema: map[string]any{
		"type":       "object",
		"properties": map[string]any{"item": map[string]any{"type": "string"}},
		"required":   []any{"item"},
	},
}}

Le modèle verra l'outil sous le nom client_add_todo.

2. Les annoncer dans initialize

Mettez la liste dans clientCapabilities._meta, sous org.mini-me/tools :

_, err := conn.Initialize(ctx, sdk.InitializeRequest{
	ProtocolVersion: sdk.ProtocolVersionNumber,
	ClientInfo:      &sdk.Implementation{Name: "my-client", Version: "1.0.0"},
	ClientCapabilities: sdk.ClientCapabilities{
		Meta: map[string]any{"org.mini-me/tools": tools},
	},
})

C'est tout ce dont mm a besoin avec la configuration par défaut (acp.clientTools.discovery: meta) : chaque session ouverte ensuite a les outils.

3. Répondre aux appels

Votre type client (celui passé à sdk.NewClientSideConnection) implémente sdk.ExtensionMethodHandler. Le SDK lui passe chaque requête dont la méthode commence par _ :

var _ sdk.ExtensionMethodHandler = (*myClient)(nil)

func (c *myClient) HandleExtensionMethod(ctx context.Context, method string, params json.RawMessage) (any, error) {
	switch method {
	case "_com.example/todo/add":
		var args struct {
			Item string `json:"item"`
			Meta struct {
				SessionID string `json:"org.mini-me/sessionId"`
			} `json:"_meta"`
		}
		if err := json.Unmarshal(params, &args); err != nil {
			return nil, sdk.NewInvalidParams(map[string]any{"error": err.Error()})
		}
		c.todos = append(c.todos, args.Item)
		return textResult(fmt.Sprintf("added %q", args.Item), false), nil
	}
	return nil, sdk.NewMethodNotFound(method)
}

// textResult is the answer shape mm reads first.
func textResult(text string, isError bool) map[string]any {
	return map[string]any{
		"content": []map[string]any{{"type": "text", "text": text}},
		"isError": isError,
	}
}
  • Les arguments du modèle sont au premier niveau de params ; _meta["org.mini-me/sessionId"] indique quelle session a appelé.
  • Répondez à un échec par isError: true et un texte dont le modèle peut se servir, plutôt que par une erreur JSON-RPC : les deux arrivent au modèle, mais le texte, c'est vous qui l'écrivez.
  • Gardez le handler sûr en accès concurrent : le SDK traite chaque requête dans sa propre goroutine.

4. Vérifier que mm les voit

Lancez mm et lisez son stderr. Après initialize, il affiche :

[acp] client tools (meta): client_add_todo

Une entrée qu'il n'a pas pu utiliser est signalée sur sa propre ligne ([acp] client tools: entry 0 skipped: …), avec la raison.

Variantes

  • La liste dépend de la session (son cwd, un utilisateur) : mettez discovery: request dans le fichier d'agent, annoncez seulement "org.mini-me/tools": true, et répondez à _org.mini-me/tools/list dans HandleExtensionMethod avec map[string]any{"tools": tools}. mm l'envoie pendant session/new, session/load et session/resume, avant d'y répondre ; le SDK vous permet de répondre pendant que votre appel à NewSession attend.

    acp:
      clientTools:
        discovery: request
    
  • Chaque appel doit être confirmé : mettez acp.clientTools.permissions: ask. mm envoie alors session/request_permission avant chaque appel, avec le titre client: <name> ; répondez-y dans votre méthode RequestPermission. Avec la valeur par défaut auto, cela n'arrive que si le fichier d'agent dit yolo: false.

  • Outils lents : augmentez acp.clientTools.timeout (30s par défaut). Au-delà, le modèle lit une erreur et le tour continue.

  • Avec le paquet minime de demo.acp.sdk/go : les étapes 1 à 3 se résument à minime.Options{Tools: []minime.Tool{…}}, chaque Tool ayant une fonction Handle ; ToolDiscovery: minime.DiscoveryRequest choisit le second mode. go run ./examples/clienttools lance un exemple complet.

Voir aussi

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Proposer des outils depuis votre client ACP

Ce guide montre comment un programme Go qui pilote `mm -acp` donne à l'agent ses propres outils : des fonctions de votre programme que le modèle appelle comme ses outils intégrés (les buffers ouverts d'un éditeur, les données d'une application, une liste de tâches…). Il suppose que votre programme est déjà un client ACP de mm, écrit avec [`github.com/coder/acp-go-sdk`](https://github.com/coder/acp-go-sdk) (v0.13.5, la version qu'utilise mm). Le protocole exact est dans la [spécification des outils du client](../reference/acp-client-tools.md).

## Étapes

### 1. Décrire vos outils

Une description par outil : un nom, une description pour le modèle, la méthode d'extension que mm appellera (elle doit commencer par `_`), et le schéma JSON des arguments.

```go
type toolSpec struct {
	Name        string         `json:"name"`
	Description string         `json:"description,omitempty"`
	Method      string         `json:"method"`
	InputSchema map[string]any `json:"inputSchema,omitempty"`
}

var tools = []toolSpec{{
	Name:        "add_todo",
	Description: "Add one item to the user's to-do list.",
	Method:      "_com.example/todo/add",
	InputSchema: map[string]any{
		"type":       "object",
		"properties": map[string]any{"item": map[string]any{"type": "string"}},
		"required":   []any{"item"},
	},
}}
```

Le modèle verra l'outil sous le nom `client_add_todo`.

### 2. Les annoncer dans `initialize`

Mettez la liste dans `clientCapabilities._meta`, sous `org.mini-me/tools` :

```go
_, err := conn.Initialize(ctx, sdk.InitializeRequest{
	ProtocolVersion: sdk.ProtocolVersionNumber,
	ClientInfo:      &sdk.Implementation{Name: "my-client", Version: "1.0.0"},
	ClientCapabilities: sdk.ClientCapabilities{
		Meta: map[string]any{"org.mini-me/tools": tools},
	},
})
```

C'est tout ce dont mm a besoin avec la configuration par défaut (`acp.clientTools.discovery: meta`) : chaque session ouverte ensuite a les outils.

### 3. Répondre aux appels

Votre type client (celui passé à `sdk.NewClientSideConnection`) implémente `sdk.ExtensionMethodHandler`. Le SDK lui passe chaque requête dont la méthode commence par `_` :

```go
var _ sdk.ExtensionMethodHandler = (*myClient)(nil)

func (c *myClient) HandleExtensionMethod(ctx context.Context, method string, params json.RawMessage) (any, error) {
	switch method {
	case "_com.example/todo/add":
		var args struct {
			Item string `json:"item"`
			Meta struct {
				SessionID string `json:"org.mini-me/sessionId"`
			} `json:"_meta"`
		}
		if err := json.Unmarshal(params, &args); err != nil {
			return nil, sdk.NewInvalidParams(map[string]any{"error": err.Error()})
		}
		c.todos = append(c.todos, args.Item)
		return textResult(fmt.Sprintf("added %q", args.Item), false), nil
	}
	return nil, sdk.NewMethodNotFound(method)
}

// textResult is the answer shape mm reads first.
func textResult(text string, isError bool) map[string]any {
	return map[string]any{
		"content": []map[string]any{{"type": "text", "text": text}},
		"isError": isError,
	}
}
```

- Les arguments du modèle sont au premier niveau de `params` ; `_meta["org.mini-me/sessionId"]` indique quelle session a appelé.
- Répondez à un échec par `isError: true` et un texte dont le modèle peut se servir, plutôt que par une erreur JSON-RPC : les deux arrivent au modèle, mais le texte, c'est vous qui l'écrivez.
- Gardez le handler sûr en accès concurrent : le SDK traite chaque requête dans sa propre goroutine.

### 4. Vérifier que mm les voit

Lancez mm et lisez son stderr. Après `initialize`, il affiche :

```
[acp] client tools (meta): client_add_todo
```

Une entrée qu'il n'a pas pu utiliser est signalée sur sa propre ligne (`[acp] client tools: entry 0 skipped: …`), avec la raison.

## Variantes

- **La liste dépend de la session** (son `cwd`, un utilisateur) : mettez `discovery: request` dans le fichier d'agent, annoncez seulement `"org.mini-me/tools": true`, et répondez à `_org.mini-me/tools/list` dans `HandleExtensionMethod` avec `map[string]any{"tools": tools}`. mm l'envoie pendant `session/new`, `session/load` et `session/resume`, avant d'y répondre ; le SDK vous permet de répondre pendant que votre appel à `NewSession` attend.

  ```yaml
  acp:
    clientTools:
      discovery: request
  ```

- **Chaque appel doit être confirmé** : mettez `acp.clientTools.permissions: ask`. mm envoie alors `session/request_permission` avant chaque appel, avec le titre `client: <name>` ; répondez-y dans votre méthode `RequestPermission`. Avec la valeur par défaut `auto`, cela n'arrive que si le fichier d'agent dit `yolo: false`.
- **Outils lents** : augmentez `acp.clientTools.timeout` (`30s` par défaut). Au-delà, le modèle lit une erreur et le tour continue.
- **Avec le paquet `minime`** de `demo.acp.sdk/go` : les étapes 1 à 3 se résument à `minime.Options{Tools: []minime.Tool{…}}`, chaque `Tool` ayant une fonction `Handle` ; `ToolDiscovery: minime.DiscoveryRequest` choisit le second mode. `go run ./examples/clienttools` lance un exemple complet.

## Voir aussi

- [Spécification des outils du client](../reference/acp-client-tools.md) — le JSON exact, la validation d'une liste, les erreurs
- [Fichier de configuration — clés de `acp`](../reference/configuration.md#clés-de-acp)
- [Piloter mini-me depuis un programme](drive-mini-me-from-a-program.md)