@falkenslab/agent-kit 0.10.1 → 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/README.md +91 -97
- package/dist/core/agentSpec.d.ts +31 -1
- package/dist/core/hooks/stepGate.js +3 -2
- package/dist/core/language.d.ts +39 -0
- package/dist/core/language.js +59 -0
- package/dist/core/messages/de.d.ts +2 -0
- package/dist/core/messages/de.js +103 -0
- package/dist/core/messages/en.d.ts +90 -0
- package/dist/core/messages/en.js +102 -0
- package/dist/core/messages/es.d.ts +2 -0
- package/dist/core/messages/es.js +103 -0
- package/dist/core/messages/fr.d.ts +2 -0
- package/dist/core/messages/fr.js +103 -0
- package/dist/core/messages/index.d.ts +23 -0
- package/dist/core/messages/index.js +67 -0
- package/dist/core/runs.d.ts +51 -0
- package/dist/core/runs.js +194 -0
- package/dist/core/session.d.ts +8 -0
- package/dist/core/session.js +42 -7
- package/dist/core/toolLabels.d.ts +2 -1
- package/dist/core/toolLabels.js +31 -51
- package/dist/core/tools/humanApproval.js +3 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/tui/chatTui.d.ts +23 -2
- package/dist/tui/chatTui.js +71 -7
- package/dist/tui/claudeAuth.d.ts +3 -1
- package/dist/tui/claudeAuth.js +12 -17
- package/dist/tui/consoleRenderer.js +2 -1
- package/dist/tui/ink/PromptInput.d.ts +3 -4
- package/dist/tui/ink/PromptInput.js +30 -17
- package/dist/tui/ink/SessionView.js +16 -15
- package/dist/tui/ink/inkInteraction.js +4 -7
- package/dist/tui/ink/progressView.d.ts +6 -0
- package/dist/tui/ink/progressView.js +2 -0
- package/dist/tui/ink/promptEditing.d.ts +11 -5
- package/dist/tui/ink/promptEditing.js +28 -3
- package/dist/tui/ink/runChatInk.d.ts +25 -2
- package/dist/tui/ink/runChatInk.js +156 -48
- package/dist/tui/ink/sessionModel.d.ts +10 -0
- package/dist/tui/ink/sessionModel.js +27 -2
- package/dist/tui/ink/toolGroup.d.ts +2 -1
- package/dist/tui/ink/toolGroup.js +5 -18
- package/dist/tui/ink/wizard.d.ts +6 -0
- package/dist/tui/ink/wizard.js +4 -1
- package/dist/tui/language.d.ts +5 -0
- package/dist/tui/language.js +11 -0
- package/dist/tui/runs.d.ts +27 -0
- package/dist/tui/runs.js +30 -0
- package/dist/tui/terminalInteraction.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,97 +1,91 @@
|
|
|
1
|
-
# agent-kit
|
|
2
|
-
|
|
3
|
-
A foundation for building AI agents on top of the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk). It isn't an agent itself: it solves once what every agent needs (human oversight, safety, memory and a good terminal interface), so each concrete agent only has to write what belongs to its own domain: what it knows how to do, with which tools, and how it talks.
|
|
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
|
-
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Each
|
|
63
|
-
|
|
64
|
-
await
|
|
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
|
-
To run a single test file:
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
npx tsx --test test/tui/promptErrors.test.ts
|
|
97
|
-
```
|
|
1
|
+
# agent-kit
|
|
2
|
+
|
|
3
|
+
A foundation for building AI agents on top of the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk). It isn't an agent itself: it solves once what every agent needs (human oversight, safety, memory and a good terminal interface), so each concrete agent only has to write what belongs to its own domain: what it knows how to do, with which tools, and how it talks.
|
|
4
|
+
|
|
5
|
+
## What an agent built with it can do
|
|
6
|
+
|
|
7
|
+
- **Work at different levels of oversight.** Autonomous, guided (it asks for permission before anything that can't be undone or that other people will see) or step by step (it asks before every action). Within the same conversation you can switch from guided to step by step and back.
|
|
8
|
+
- **Ask a person for help.** It asks for approvals, or stops so someone can do something by hand, such as signing in to a website. It can be answered from the keyboard or from another program driving it, for example a desktop app.
|
|
9
|
+
- **Remember between sessions.** It keeps its own knowledge base, a small wiki of notes that grows with every session, and keeps the original documents you give it or that it downloads untouched. Each conversation stays in the project's folder, so you can pick it up again with `--continue` (the latest one) or `/resume` (any of them).
|
|
10
|
+
- **Speak your language.** Its interface comes in English, Spanish, French or German, the system's by default or the one you ask for with `--language=fr`, and it answers in that language unless you write to it in another one.
|
|
11
|
+
- **Delegate to subagents safely.** Only to the ones it declares, always waiting for their result, and without the main agent being able to slip past its own limits through them.
|
|
12
|
+
- **Stay within limits.** It only reads and writes in the folders that belong to it, and never in protected files, such as one holding passwords.
|
|
13
|
+
- **Use external tools.** MCP servers of its own or of the project, and skills and commands organized in plugins.
|
|
14
|
+
- **Leave a trail.** It records every action and the whole conversation, with secrets hidden.
|
|
15
|
+
- **Chat in a terminal the way Claude Code does.** Full screen, with the reply written live and its markdown already formatted, the tools it uses summed up in one line (Ctrl+O unfolds it), panels for approvals, history and search, a suggestion for the next message, pasted blocks, file mentions with `@`, mouse selection (right-click to copy), and the agent's status in the tab and in the Windows taskbar.
|
|
16
|
+
- **Also work without a terminal.** The same foundation runs inside a desktop app or a server, which bring their own interface.
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### Captain Whiskers
|
|
21
|
+
|
|
22
|
+
[Captain Whiskers](./examples/captain-whiskers) is a toy agent to see the kit in action: a retired pirate cat who tells jokes in the terminal, in your language. It starts full screen with its logo and has a small crew of subagents: one looks for new jokes on the web, another rates them before they're told, and a third tells the time with a tool of the captain's own. It lets you try the different levels of oversight and is the best starting point for an agent of your own. Its README explains how to run it.
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
### teacher-agent
|
|
27
|
+
|
|
28
|
+
[teacher-agent](https://github.com/falkenslab/teacher-agent) is a real assistant for Moodle teachers. It signs in with your account in a Chrome window and works as you would: it grades submissions, answers in the forum, creates or reviews content and sums up how the class is going. It asks for your permission before publishing anything students will see, and takes notes about the course to remember everything in the next session.
|
|
29
|
+
|
|
30
|
+
Oversight, memory, safety and the chat come from the kit; teacher-agent brings what it knows about Moodle and driving the browser.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
npm install @falkenslab/agent-kit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
To try changes to the kit without publishing them, point to a local clone with `"file:../agent-kit"` in your `package.json` and build it with `npm run build` after each change.
|
|
39
|
+
|
|
40
|
+
Requires Node.js 20 or later.
|
|
41
|
+
|
|
42
|
+
## A minimal agent
|
|
43
|
+
|
|
44
|
+
An agent only describes what belongs to it (who it is, which MCP servers, skills and subagents it has) and picks a level of oversight; the kit sets up the session and the chat:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import path from "node:path";
|
|
48
|
+
import { buildSessionOptions, ensureClaudeAuth, runChatInk, type AgentSpec, type BaseSessionConfig } from "@falkenslab/agent-kit";
|
|
49
|
+
|
|
50
|
+
// The only part specific to the agent: who it is and what it has.
|
|
51
|
+
const spec: AgentSpec<BaseSessionConfig> = {
|
|
52
|
+
buildSystemPrompt: () => "You are a pirate cat who tells jokes. Always answer in character.",
|
|
53
|
+
buildMcpServers: () => ({}), // its own MCP servers, if any
|
|
54
|
+
pluginRoots: () => [], // folders with skills and commands
|
|
55
|
+
buildSubagents: () => undefined, // subagents, if it delegates to any
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
await ensureClaudeAuth(); // offers to create a Claude token if it finds none
|
|
59
|
+
|
|
60
|
+
const config: BaseSessionConfig = { mode: "guided", projectDir: process.cwd() };
|
|
61
|
+
|
|
62
|
+
// Each run gets a folder of its own under .run/ (keep it out of git): its log, its
|
|
63
|
+
// transcript and the conversation, to pick it up again with --continue or /resume.
|
|
64
|
+
await runChatInk((run) => buildSessionOptions(config, run.dir, spec, { run }), {
|
|
65
|
+
runsDir: path.resolve(".run"),
|
|
66
|
+
header: { title: "My agent" },
|
|
67
|
+
mode: config.mode, // Shift+Tab switches between guided and step by step
|
|
68
|
+
fullscreen: true,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Save it as `agent.ts` in a project with the kit and `tsx` installed and `"type": "module"` in its `package.json`, and run it with `npx tsx agent.ts`. Captain Whiskers is this same skeleton with more pieces: skills, subagents and its logo.
|
|
73
|
+
|
|
74
|
+
## More details
|
|
75
|
+
|
|
76
|
+
The specification in [`.minispec/`](./.minispec/README.md) explains how each part is built and why, including the SDK behaviors checked by hand that motivate several of its safeguards. Captain Whiskers' code is the quickest way to see how an agent is put together.
|
|
77
|
+
|
|
78
|
+
## Development
|
|
79
|
+
|
|
80
|
+
| Command | What it does |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `npm run build` | Builds the kit into `dist/` |
|
|
83
|
+
| `npm run typecheck` | Checks the types without building |
|
|
84
|
+
| `npm run lint` | Checks the code style |
|
|
85
|
+
| `npm test` | Runs all the tests |
|
|
86
|
+
|
|
87
|
+
To run a single test file:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
npx tsx --test test/tui/promptErrors.test.ts
|
|
91
|
+
```
|
package/dist/core/agentSpec.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentDefinition as SdkSubagentDefinition, McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
1
|
+
import type { AgentDefinition as SdkSubagentDefinition, McpServerConfig, SettingSource } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
/**
|
|
3
3
|
* The human-supervision spectrum every agent built on this kit shares, independent of
|
|
4
4
|
* domain: "interactive" pauses before every single action, "guided" only pauses before a
|
|
@@ -42,6 +42,12 @@ export interface BaseSessionConfig {
|
|
|
42
42
|
deniedPaths?: string[];
|
|
43
43
|
/** Extra values (e.g. a password) to scrub out of the transcript log — see hooks/transcriptLogger.ts. */
|
|
44
44
|
secrets?: string[];
|
|
45
|
+
/**
|
|
46
|
+
* The language ("en", "es", "fr", "de") the agent replies in and the kit's interface uses.
|
|
47
|
+
* `--language=<code>` on the command line wins over it; without either, the system's
|
|
48
|
+
* language (see language.ts). Pass the same value to the chat, wizard or progress view.
|
|
49
|
+
*/
|
|
50
|
+
language?: string;
|
|
45
51
|
}
|
|
46
52
|
/**
|
|
47
53
|
* Everything actually *about the domain* that `buildSessionOptions()` needs but doesn't
|
|
@@ -103,6 +109,30 @@ export interface AgentSpec<TConfig extends BaseSessionConfig> {
|
|
|
103
109
|
* notes) — `knowledgePromptSection()`/`knowledgePluginRoot()` are exported to reuse the pieces.
|
|
104
110
|
*/
|
|
105
111
|
knowledgeBase?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Whether the kit tells the agent (and each subagent) to reply in the resolved language
|
|
114
|
+
* (`config.language`, `--language`, the system's), following the human if they write in
|
|
115
|
+
* another one. On by default; `false` leaves the reply language to the agent's own prompt.
|
|
116
|
+
*/
|
|
117
|
+
replyInLanguage?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Which filesystem settings the session loads (the SDK's `settingSources`): "project" is
|
|
120
|
+
* the project's `.claude/` (settings, skills, commands) and its CLAUDE.md files, "local"
|
|
121
|
+
* its `.claude/settings.local.json`, "user" the runner's own `~/.claude/` (settings,
|
|
122
|
+
* CLAUDE.md, skills). Default `["project"]`: the runner's personal Claude Code
|
|
123
|
+
* configuration (its `language`, output style, CLAUDE.md, hooks...) never reaches the
|
|
124
|
+
* agent unless asked for with "user" — the SDK's own default loads all three, and the
|
|
125
|
+
* runner's `language` setting then outranked the agent's prompt. `[]` isolates the agent
|
|
126
|
+
* from every settings file, CLAUDE.md included.
|
|
127
|
+
*/
|
|
128
|
+
settingSources?: SettingSource[];
|
|
129
|
+
/**
|
|
130
|
+
* The skills the agent offers (the SDK's `skills`): names, or `plugin:skill` for a
|
|
131
|
+
* plugin's. Default `"all"`, every skill found (the SDK's own, the project's, the
|
|
132
|
+
* plugins'). A list keeps the rest out of each turn's context; the knowledge base's own
|
|
133
|
+
* skills are added to it when the knowledge base is on. A context filter, not a sandbox.
|
|
134
|
+
*/
|
|
135
|
+
skills?: string[] | "all";
|
|
106
136
|
/**
|
|
107
137
|
* Text for the generic human-approval checkpoint (see tools/humanApproval.ts) — what
|
|
108
138
|
* counts as "publishing something visible to others" is entirely domain-specific.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { askForDecision } from "./humanInput.js";
|
|
2
|
+
import { t } from "../messages/index.js";
|
|
2
3
|
/**
|
|
3
4
|
* PreToolUse hook for "interactive" mode: pauses before every action and asks for
|
|
4
5
|
* confirmation (by keyboard or by file, see humanInput.ts), like reviewing a plan step
|
|
@@ -14,8 +15,8 @@ export function createStepGate(runDir, isActive = () => true) {
|
|
|
14
15
|
return {};
|
|
15
16
|
const pre = input;
|
|
16
17
|
const answer = await askForDecision(runDir, {
|
|
17
|
-
title:
|
|
18
|
-
lines: [
|
|
18
|
+
title: t().proposedAction,
|
|
19
|
+
lines: [t().toolLine(pre.tool_name), t().parametersLine(JSON.stringify(pre.tool_input, null, 2))],
|
|
19
20
|
});
|
|
20
21
|
if (answer === "q") {
|
|
21
22
|
return {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The languages the kit's own texts come in. */
|
|
2
|
+
export type Language = "en" | "es" | "fr" | "de";
|
|
3
|
+
export declare const SUPPORTED_LANGUAGES: readonly Language[];
|
|
4
|
+
/** Each language's name in English, as the model is told it (the kit's text for the model stays in English). */
|
|
5
|
+
export declare const LANGUAGE_NAMES: Record<Language, string>;
|
|
6
|
+
/** Where the language can come from, in order of precedence. */
|
|
7
|
+
export interface LanguageSources {
|
|
8
|
+
/** The process's arguments; `--language=<code>` wins over everything else. */
|
|
9
|
+
argv?: readonly string[];
|
|
10
|
+
/** The agent's own choice (its code or configuration). */
|
|
11
|
+
option?: string;
|
|
12
|
+
/** The system's locale, e.g. "es-ES" (`Intl`). */
|
|
13
|
+
locale?: string;
|
|
14
|
+
/** The environment, for `LC_ALL`, `LC_MESSAGES` and `LANG` (e.g. "fr_FR.UTF-8"). */
|
|
15
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
16
|
+
}
|
|
17
|
+
export interface ResolvedLanguage {
|
|
18
|
+
language: Language;
|
|
19
|
+
/** One line per code that was asked for and isn't supported (English text, for the caller to show). */
|
|
20
|
+
warnings: string[];
|
|
21
|
+
}
|
|
22
|
+
/** "es", "ES", "es-ES", "es_ES.UTF-8" → "es"; anything unsupported → null. */
|
|
23
|
+
export declare function toLanguage(code: string | undefined): Language | null;
|
|
24
|
+
/** The value of `--language=<code>` (or `--language <code>`) in `argv`, if any. */
|
|
25
|
+
export declare function languageArgument(argv: readonly string[]): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* The language for the kit's texts and the agent's replies: `--language=<code>`, then the
|
|
28
|
+
* agent's option, then the system's language, then English. A code that is asked for but
|
|
29
|
+
* isn't supported falls through to the next source, with a warning. Pure: `detectLanguage()`
|
|
30
|
+
* fills the sources from the running process.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveLanguage(sources: LanguageSources): ResolvedLanguage;
|
|
33
|
+
/** `resolveLanguage()` with the running process's arguments, locale and environment. */
|
|
34
|
+
export declare function detectLanguage(option?: string): ResolvedLanguage;
|
|
35
|
+
/**
|
|
36
|
+
* The line appended to the agent's (and each subagent's) prompt so it answers in the
|
|
37
|
+
* resolved language, but follows the human if they write in another one.
|
|
38
|
+
*/
|
|
39
|
+
export declare function replyLanguageInstruction(language: Language): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const SUPPORTED_LANGUAGES = ["en", "es", "fr", "de"];
|
|
2
|
+
/** Each language's name in English, as the model is told it (the kit's text for the model stays in English). */
|
|
3
|
+
export const LANGUAGE_NAMES = { en: "English", es: "Spanish", fr: "French", de: "German" };
|
|
4
|
+
/** "es", "ES", "es-ES", "es_ES.UTF-8" → "es"; anything unsupported → null. */
|
|
5
|
+
export function toLanguage(code) {
|
|
6
|
+
const base = code?.trim().toLowerCase().split(/[-_.@]/)[0];
|
|
7
|
+
return SUPPORTED_LANGUAGES.find((language) => language === base) ?? null;
|
|
8
|
+
}
|
|
9
|
+
/** The value of `--language=<code>` (or `--language <code>`) in `argv`, if any. */
|
|
10
|
+
export function languageArgument(argv) {
|
|
11
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12
|
+
const arg = argv[i];
|
|
13
|
+
if (arg.startsWith("--language="))
|
|
14
|
+
return arg.slice("--language=".length);
|
|
15
|
+
if (arg === "--language")
|
|
16
|
+
return argv[i + 1];
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The language for the kit's texts and the agent's replies: `--language=<code>`, then the
|
|
22
|
+
* agent's option, then the system's language, then English. A code that is asked for but
|
|
23
|
+
* isn't supported falls through to the next source, with a warning. Pure: `detectLanguage()`
|
|
24
|
+
* fills the sources from the running process.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveLanguage(sources) {
|
|
27
|
+
const warnings = [];
|
|
28
|
+
const asked = (code, from) => {
|
|
29
|
+
if (code === undefined || code.trim() === "")
|
|
30
|
+
return null;
|
|
31
|
+
const language = toLanguage(code);
|
|
32
|
+
if (!language)
|
|
33
|
+
warnings.push(`Unsupported language "${code}" (${from}); supported: ${SUPPORTED_LANGUAGES.join(", ")}.`);
|
|
34
|
+
return language;
|
|
35
|
+
};
|
|
36
|
+
const env = sources.env ?? {};
|
|
37
|
+
const system = [sources.locale, env.LC_ALL, env.LC_MESSAGES, env.LANG].map(toLanguage).find((language) => language !== null);
|
|
38
|
+
const language = asked(sources.argv ? languageArgument(sources.argv) : undefined, "--language") ?? asked(sources.option, "language option") ?? system ?? "en";
|
|
39
|
+
return { language, warnings };
|
|
40
|
+
}
|
|
41
|
+
/** `resolveLanguage()` with the running process's arguments, locale and environment. */
|
|
42
|
+
export function detectLanguage(option) {
|
|
43
|
+
let locale;
|
|
44
|
+
try {
|
|
45
|
+
locale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
locale = undefined;
|
|
49
|
+
}
|
|
50
|
+
return resolveLanguage({ argv: process.argv.slice(2), option, locale, env: process.env });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The line appended to the agent's (and each subagent's) prompt so it answers in the
|
|
54
|
+
* resolved language, but follows the human if they write in another one.
|
|
55
|
+
*/
|
|
56
|
+
export function replyLanguageInstruction(language) {
|
|
57
|
+
const name = LANGUAGE_NAMES[language];
|
|
58
|
+
return `Language: reply in ${name}, whatever language these instructions, your skills or the human's name are in. Switch to another language only when the human's message is clearly written in it; a greeting, a slash command or a single word doesn't count.`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const plural = (count, one, many) => (count === 1 ? one : many);
|
|
2
|
+
const MODES = { autonomous: "autonom", guided: "geführt", interactive: "interaktiv" };
|
|
3
|
+
export const de = {
|
|
4
|
+
thinking: "Denkt nach…",
|
|
5
|
+
escToInterrupt: "Esc zum Unterbrechen",
|
|
6
|
+
workedFor: (seconds) => `${seconds}s gearbeitet`,
|
|
7
|
+
turns: (count) => `${count} ${plural(count, "Runde", "Runden")}`,
|
|
8
|
+
tokens: (input, output) => `${input} ein / ${output} aus`,
|
|
9
|
+
context: (percent) => `Kontext ${percent}%`,
|
|
10
|
+
mode: (mode) => MODES[mode],
|
|
11
|
+
switchModeKey: "⇧Tab",
|
|
12
|
+
modeLocked: (mode) => (mode ? `(der Modus ${MODES[mode]} kann während der Sitzung nicht gewechselt werden)` : "(der Modus kann während der Sitzung nicht gewechselt werden)"),
|
|
13
|
+
linesBelow: (count) => `↓ ${count} weitere ${plural(count, "Zeile", "Zeilen")} (Strg+Ende)`,
|
|
14
|
+
copiedCharacters: (count) => `${count} ${plural(count, "Zeichen", "Zeichen")} kopiert`,
|
|
15
|
+
queued: (line) => `in der Warteschlange: ${line}`,
|
|
16
|
+
interrupted: "(unterbrochen)",
|
|
17
|
+
copiedReply: (characters) => `(letzte Antwort kopiert: ${characters} Zeichen)`,
|
|
18
|
+
nothingToCopy: "(noch nichts zu kopieren)",
|
|
19
|
+
unknownCommand: (command) => `Unbekannter Befehl: /${command}`,
|
|
20
|
+
mcpFailed: (servers) => `Einige MCP-Server konnten keine Verbindung herstellen: ${servers}`,
|
|
21
|
+
resumeTitle: "Ein Gespräch fortsetzen",
|
|
22
|
+
resumeHint: "↑/↓ wählen · Enter fortsetzen · Esc abbrechen",
|
|
23
|
+
resumeQuestion: "Nummer des Gesprächs, das fortgesetzt werden soll (Enter zum Abbrechen): ",
|
|
24
|
+
noEarlierRuns: "(keine früheren Gespräche zum Fortsetzen)",
|
|
25
|
+
currentRun: "(dieses)",
|
|
26
|
+
resumed: (date) => `(Gespräch vom ${date} fortgesetzt)`,
|
|
27
|
+
suggestionKey: "Tab",
|
|
28
|
+
reverseSearch: (query) => `(Rückwärtssuche)'${query}': `,
|
|
29
|
+
pastedText: (id, extraLines) => `[Eingefügter Text #${id} +${extraLines} ${plural(extraLines, "Zeile", "Zeilen")}]`,
|
|
30
|
+
shortcuts: [
|
|
31
|
+
"Enter senden · \\ + Enter oder Strg+J neue Zeile · Tab vervollständigen oder den Vorschlag übernehmen",
|
|
32
|
+
"↑/↓ Verlauf · Strg+R im Verlauf suchen · ↑ bei leerer Eingabe bearbeitet die letzte wartende Nachricht",
|
|
33
|
+
"Strg+W Wort löschen · Strg+K bis zum Zeilenende · Strg+U leeren · Strg+←/→ wortweise bewegen",
|
|
34
|
+
"@ eine Datei erwähnen · /copy letzte Antwort kopieren · Umschalt+Tab Modus wechseln · Strg+O Werkzeuge aufklappen",
|
|
35
|
+
"Esc unterbrechen · Strg+C unterbrechen oder beenden · Bild↑/Bild↓ oder Mausrad scrollen · Strg+Ende ganz nach unten",
|
|
36
|
+
"Ziehen zum Markieren, Rechtsklick zum Kopieren (Vollbild)",
|
|
37
|
+
"/resume ein früheres Gespräch fortsetzen · --continue beim Start setzt das letzte fort",
|
|
38
|
+
],
|
|
39
|
+
moreLines: (count) => `… (${count} weitere Zeilen)`,
|
|
40
|
+
proceed: "Möchtest du fortfahren?",
|
|
41
|
+
yes: "Ja",
|
|
42
|
+
no: "Nein",
|
|
43
|
+
stop: "Anhalten",
|
|
44
|
+
doneContinue: "Erledigt, weiter",
|
|
45
|
+
approved: "✔ Genehmigt",
|
|
46
|
+
rejected: "✘ Abgelehnt",
|
|
47
|
+
stopped: "■ Angehalten",
|
|
48
|
+
done: "✔ Erledigt",
|
|
49
|
+
answeredByFile: "(über die Antwortdatei beantwortet)",
|
|
50
|
+
terminalQuestion: "Fortfahren erlauben? [Y/n/q] ",
|
|
51
|
+
proposedAction: "Vorgeschlagene Aktion",
|
|
52
|
+
toolLine: (tool) => `Werkzeug: ${tool}`,
|
|
53
|
+
parametersLine: (parameters) => `Parameter: ${parameters}`,
|
|
54
|
+
approvalTitle: "Vor dem Veröffentlichen ist eine menschliche Bestätigung nötig",
|
|
55
|
+
summaryLine: (summary) => `Zusammenfassung: ${summary}`,
|
|
56
|
+
toolPhrases: {
|
|
57
|
+
Read: ["hat {n} Datei gelesen", "hat {n} Dateien gelesen"],
|
|
58
|
+
Write: ["hat {n} Datei geschrieben", "hat {n} Dateien geschrieben"],
|
|
59
|
+
Edit: ["hat {n} Datei bearbeitet", "hat {n} Dateien bearbeitet"],
|
|
60
|
+
Glob: ["hat Dateien aufgelistet", "hat {n}-mal Dateien aufgelistet"],
|
|
61
|
+
Grep: ["hat {n}-mal gesucht", "hat {n}-mal gesucht"],
|
|
62
|
+
Bash: ["hat {n} Befehl ausgeführt", "hat {n} Befehle ausgeführt"],
|
|
63
|
+
WebSearch: ["hat im Web gesucht", "hat {n}-mal im Web gesucht"],
|
|
64
|
+
WebFetch: ["hat {n} Seite geöffnet", "hat {n} Seiten geöffnet"],
|
|
65
|
+
Skill: ["hat {n} Skill verwendet", "hat {n} Skills verwendet"],
|
|
66
|
+
Agent: ["hat {n} Subagenten gestartet", "hat {n} Subagenten gestartet"],
|
|
67
|
+
Task: ["hat {n} Subagenten gestartet", "hat {n} Subagenten gestartet"],
|
|
68
|
+
},
|
|
69
|
+
otherTools: ["hat {n} Werkzeug verwendet", "hat {n} Werkzeuge verwendet"],
|
|
70
|
+
noOutput: "(keine Ausgabe)",
|
|
71
|
+
error: "Fehler",
|
|
72
|
+
moreResultLines: (count) => `(+${count} ${plural(count, "Zeile", "Zeilen")})`,
|
|
73
|
+
earlierCalls: (count) => `… ${count} frühere`,
|
|
74
|
+
labels: {
|
|
75
|
+
askingApproval: (summary) => `Bittet um menschliche Genehmigung: ${summary}`,
|
|
76
|
+
waitingManual: "Wartet auf einen manuellen Eingriff",
|
|
77
|
+
savingToSources: (destination) => `Speichert eine Datei in sources/${destination}`,
|
|
78
|
+
reading: (file) => `Liest ${file}`,
|
|
79
|
+
writing: (file) => `Schreibt in ${file}`,
|
|
80
|
+
editing: (file) => `Bearbeitet ${file}`,
|
|
81
|
+
aFile: "eine Datei",
|
|
82
|
+
findingFiles: (pattern) => `Sucht Dateien, die zu "${pattern}" passen`,
|
|
83
|
+
searchingContents: (pattern) => `Sucht "${pattern}" in den Dateien`,
|
|
84
|
+
running: (command) => `Führt "${command}" aus`,
|
|
85
|
+
delegating: (subagent) => `Delegiert an "${subagent}"`,
|
|
86
|
+
delegatingTask: (subagent, description) => `Delegiert an "${subagent}": ${description}`,
|
|
87
|
+
aSubagent: "einen Subagenten",
|
|
88
|
+
fetching: (url) => `Öffnet ${url}`,
|
|
89
|
+
aPage: "eine Seite",
|
|
90
|
+
searchingWeb: (query) => `Sucht im Web nach "${query}"`,
|
|
91
|
+
applyingSkill: (skill) => `Wendet den Skill "${skill}" an`,
|
|
92
|
+
aSkill: "einen Skill",
|
|
93
|
+
},
|
|
94
|
+
auth: {
|
|
95
|
+
noToken: "Es wurde kein Claude-Authentifizierungstoken gefunden",
|
|
96
|
+
noTokenDetail: "(weder die Umgebungsvariable CLAUDE_CODE_OAUTH_TOKEN noch ein im Code übergebenes).",
|
|
97
|
+
generateQuestion: 'Jetzt eines mit "claude setup-token" erzeugen? (erfordert ein Claude-Pro/Max-Abonnement)',
|
|
98
|
+
cantStart: "Der Agent kann ohne Token nicht starten. Setze CLAUDE_CODE_OAUTH_TOKEN von Hand (oder starte erneut und lass es erzeugen) und versuche es noch einmal.",
|
|
99
|
+
generatingHeading: "=== Claude-Authentifizierungstoken wird erzeugt ===",
|
|
100
|
+
browserWillOpen: "Zum Anmelden öffnet sich ein Browser; folge den Anweisungen, die der Befehl unten ausgibt.",
|
|
101
|
+
generated: "Token für diese Ausführung erzeugt. Speichere es selbst (z. B. CLAUDE_CODE_OAUTH_TOKEN im Profil deiner Shell), um diesen Schritt beim nächsten Mal zu überspringen.",
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Mode } from "../agentSpec.js";
|
|
2
|
+
/** How a tool counts in a folded group's summary: the phrase for one call and for several, "{n}" standing for the count. */
|
|
3
|
+
export type ToolPhrase = [one: string, many: string];
|
|
4
|
+
/**
|
|
5
|
+
* Every text the kit shows a person, in one language. Texts for the model (tool
|
|
6
|
+
* descriptions, hook deny reasons, the knowledge base's prompt section) aren't here: they
|
|
7
|
+
* stay in English whatever the language.
|
|
8
|
+
*/
|
|
9
|
+
export interface Messages {
|
|
10
|
+
thinking: string;
|
|
11
|
+
escToInterrupt: string;
|
|
12
|
+
workedFor(seconds: number): string;
|
|
13
|
+
turns(count: number): string;
|
|
14
|
+
tokens(input: string, output: string): string;
|
|
15
|
+
context(percent: number): string;
|
|
16
|
+
mode(mode: Mode): string;
|
|
17
|
+
switchModeKey: string;
|
|
18
|
+
modeLocked(mode: Mode | undefined): string;
|
|
19
|
+
linesBelow(count: number): string;
|
|
20
|
+
copiedCharacters(count: number): string;
|
|
21
|
+
queued(line: string): string;
|
|
22
|
+
interrupted: string;
|
|
23
|
+
copiedReply(characters: number): string;
|
|
24
|
+
nothingToCopy: string;
|
|
25
|
+
unknownCommand(command: string): string;
|
|
26
|
+
mcpFailed(servers: string): string;
|
|
27
|
+
resumeTitle: string;
|
|
28
|
+
resumeHint: string;
|
|
29
|
+
resumeQuestion: string;
|
|
30
|
+
noEarlierRuns: string;
|
|
31
|
+
currentRun: string;
|
|
32
|
+
resumed(date: string): string;
|
|
33
|
+
suggestionKey: string;
|
|
34
|
+
reverseSearch(query: string): string;
|
|
35
|
+
pastedText(id: number, extraLines: number): string;
|
|
36
|
+
shortcuts: string[];
|
|
37
|
+
moreLines(count: number): string;
|
|
38
|
+
proceed: string;
|
|
39
|
+
yes: string;
|
|
40
|
+
no: string;
|
|
41
|
+
stop: string;
|
|
42
|
+
doneContinue: string;
|
|
43
|
+
approved: string;
|
|
44
|
+
rejected: string;
|
|
45
|
+
stopped: string;
|
|
46
|
+
done: string;
|
|
47
|
+
answeredByFile: string;
|
|
48
|
+
terminalQuestion: string;
|
|
49
|
+
proposedAction: string;
|
|
50
|
+
toolLine(tool: string): string;
|
|
51
|
+
parametersLine(parameters: string): string;
|
|
52
|
+
approvalTitle: string;
|
|
53
|
+
summaryLine(summary: string): string;
|
|
54
|
+
toolPhrases: Record<string, ToolPhrase>;
|
|
55
|
+
otherTools: ToolPhrase;
|
|
56
|
+
noOutput: string;
|
|
57
|
+
error: string;
|
|
58
|
+
moreResultLines(count: number): string;
|
|
59
|
+
earlierCalls(count: number): string;
|
|
60
|
+
labels: {
|
|
61
|
+
askingApproval(summary: string): string;
|
|
62
|
+
waitingManual: string;
|
|
63
|
+
savingToSources(destination: string): string;
|
|
64
|
+
reading(file: string): string;
|
|
65
|
+
writing(file: string): string;
|
|
66
|
+
editing(file: string): string;
|
|
67
|
+
aFile: string;
|
|
68
|
+
findingFiles(pattern: string): string;
|
|
69
|
+
searchingContents(pattern: string): string;
|
|
70
|
+
running(command: string): string;
|
|
71
|
+
delegating(subagent: string): string;
|
|
72
|
+
delegatingTask(subagent: string, description: string): string;
|
|
73
|
+
aSubagent: string;
|
|
74
|
+
fetching(url: string): string;
|
|
75
|
+
aPage: string;
|
|
76
|
+
searchingWeb(query: string): string;
|
|
77
|
+
applyingSkill(skill: string): string;
|
|
78
|
+
aSkill: string;
|
|
79
|
+
};
|
|
80
|
+
auth: {
|
|
81
|
+
noToken: string;
|
|
82
|
+
noTokenDetail: string;
|
|
83
|
+
generateQuestion: string;
|
|
84
|
+
cantStart: string;
|
|
85
|
+
generatingHeading: string;
|
|
86
|
+
browserWillOpen: string;
|
|
87
|
+
generated: string;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export declare const en: Messages;
|