@openagents-org/agent-launcher 0.2.161 → 0.2.163
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/icons/pi.svg +1 -0
- package/package.json +1 -1
- package/registry.json +144 -0
- package/src/adapters/index.js +4 -1
- package/src/adapters/pi-launcher-provider.mjs +116 -0
- package/src/adapters/pi-stream.js +922 -0
- package/src/adapters/pi.js +1492 -0
- package/src/adapters/workspace-prompt.js +21 -0
- package/src/daemon.js +37 -2
- package/src/installer.js +20 -4
- package/src/workspace-client.js +5 -4
package/icons/pi.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Pi</title><rect x="2.8" y="5.2" width="18.4" height="3.1" rx="1.55"></rect><rect x="6.1" y="7.6" width="3.1" height="11.4" rx="1.55"></rect><rect x="14.8" y="7.6" width="3.1" height="11.4" rx="1.55"></rect></svg>
|
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -930,5 +930,149 @@
|
|
|
930
930
|
],
|
|
931
931
|
"not_ready_message": "mini-SWE-agent CLI detected. Configure a model through environment variables (MSWEA_MODEL_NAME + a provider key), a full config file (MSWEA_MINI_CONFIG_PATH), or the Model field before running a task."
|
|
932
932
|
}
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
"name": "pi",
|
|
936
|
+
"label": "Pi",
|
|
937
|
+
"description": "Earendil's Pi coding agent for the terminal — headless RPC mode, many providers",
|
|
938
|
+
"homepage": "https://pi.dev",
|
|
939
|
+
"tags": [
|
|
940
|
+
"coding",
|
|
941
|
+
"cli",
|
|
942
|
+
"open-source",
|
|
943
|
+
"rpc"
|
|
944
|
+
],
|
|
945
|
+
"builtin": true,
|
|
946
|
+
"support": {
|
|
947
|
+
"install": true,
|
|
948
|
+
"workspace": true,
|
|
949
|
+
"collaboration": true
|
|
950
|
+
},
|
|
951
|
+
"install": {
|
|
952
|
+
"binary": "pi",
|
|
953
|
+
"npm_package": "@earendil-works/pi-coding-agent",
|
|
954
|
+
"requires": [
|
|
955
|
+
"nodejs"
|
|
956
|
+
],
|
|
957
|
+
"min_version": "0.83.0",
|
|
958
|
+
"verify": "pi --version >/dev/null 2>&1",
|
|
959
|
+
"verify_win": "pi --version >nul 2>nul",
|
|
960
|
+
"macos": "npm install -g @earendil-works/pi-coding-agent@0.83.0",
|
|
961
|
+
"linux": "npm install -g @earendil-works/pi-coding-agent@0.83.0",
|
|
962
|
+
"windows": "npm install -g @earendil-works/pi-coding-agent@0.83.0"
|
|
963
|
+
},
|
|
964
|
+
"adapter": {
|
|
965
|
+
"module": "openagents.adapters.pi",
|
|
966
|
+
"class": "PiAdapter"
|
|
967
|
+
},
|
|
968
|
+
"launch": {
|
|
969
|
+
"args": []
|
|
970
|
+
},
|
|
971
|
+
"env_config": [
|
|
972
|
+
{
|
|
973
|
+
"name": "PI_PROVIDER",
|
|
974
|
+
"description": "Provider: anthropic/openai for native APIs or compatible relays, deepseek for the native DeepSeek API, openai-codex for an existing Pi subscription login, or custom.",
|
|
975
|
+
"required": false,
|
|
976
|
+
"placeholder": "anthropic",
|
|
977
|
+
"default": "anthropic",
|
|
978
|
+
"options": [
|
|
979
|
+
"anthropic",
|
|
980
|
+
"openai",
|
|
981
|
+
"deepseek",
|
|
982
|
+
"openai-codex",
|
|
983
|
+
"openrouter",
|
|
984
|
+
"google",
|
|
985
|
+
"custom"
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
"name": "PI_MODEL",
|
|
990
|
+
"description": "Exact model id exposed by the provider or relay (for example claude-sonnet-4-6, gpt-5-codex, or deepseek-v4-flash).",
|
|
991
|
+
"required": false,
|
|
992
|
+
"placeholder": "claude-sonnet-4-6"
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
"name": "PI_API_FORMAT",
|
|
996
|
+
"description": "API protocol. Keep auto for native providers; choose anthropic-messages, openai-completions, or openai-responses for a relay.",
|
|
997
|
+
"required": false,
|
|
998
|
+
"default": "auto",
|
|
999
|
+
"options": [
|
|
1000
|
+
"auto",
|
|
1001
|
+
"anthropic-messages",
|
|
1002
|
+
"openai-completions",
|
|
1003
|
+
"openai-responses"
|
|
1004
|
+
]
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
"name": "PI_BASE_URL",
|
|
1008
|
+
"description": "Optional relay/proxy base URL. Leave blank for the provider's native API. OpenAgents configures Pi automatically when this is set.",
|
|
1009
|
+
"required": false,
|
|
1010
|
+
"placeholder": "https://relay.example.com/v1"
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
"name": "PI_API_KEY",
|
|
1014
|
+
"description": "API key for the selected provider or relay. Leave blank to reuse an existing Pi /login session.",
|
|
1015
|
+
"required": false,
|
|
1016
|
+
"password": true
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
"name": "PI_THINKING",
|
|
1020
|
+
"description": "Reasoning effort: off, minimal, low, medium, high, xhigh, max. Leave blank for the model default.",
|
|
1021
|
+
"required": false,
|
|
1022
|
+
"default": "off",
|
|
1023
|
+
"options": [
|
|
1024
|
+
"off",
|
|
1025
|
+
"minimal",
|
|
1026
|
+
"low",
|
|
1027
|
+
"medium",
|
|
1028
|
+
"high",
|
|
1029
|
+
"xhigh",
|
|
1030
|
+
"max"
|
|
1031
|
+
]
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
"name": "PI_TRUST_PROJECT",
|
|
1035
|
+
"description": "Set to 1 to let Pi load project-local .pi/settings.json, extensions and skills from the working directory. OFF by default — project files are executable surface.",
|
|
1036
|
+
"required": false,
|
|
1037
|
+
"default": "0",
|
|
1038
|
+
"options": [
|
|
1039
|
+
"0",
|
|
1040
|
+
"1"
|
|
1041
|
+
]
|
|
1042
|
+
}
|
|
1043
|
+
],
|
|
1044
|
+
"check_ready": {
|
|
1045
|
+
"creds_file": "~/.pi/agent/auth.json",
|
|
1046
|
+
"creds_no_parse": true,
|
|
1047
|
+
"creds_json_has_entries": true,
|
|
1048
|
+
"env_vars": [
|
|
1049
|
+
"PI_API_KEY",
|
|
1050
|
+
"DEEPSEEK_API_KEY",
|
|
1051
|
+
"ANTHROPIC_API_KEY",
|
|
1052
|
+
"OPENAI_API_KEY",
|
|
1053
|
+
"GEMINI_API_KEY",
|
|
1054
|
+
"OPENROUTER_API_KEY"
|
|
1055
|
+
],
|
|
1056
|
+
"saved_env_key": "PI_API_KEY",
|
|
1057
|
+
"login_command": "pi",
|
|
1058
|
+
"not_ready_message": "Not configured — set a provider API key (press e), or run `pi` and use /login once.",
|
|
1059
|
+
"unreadable_message": "Pi credentials were found but could not be read. Check permissions on ~/.pi/agent, or run `pi` and sign in again."
|
|
1060
|
+
},
|
|
1061
|
+
"resolve_env": {
|
|
1062
|
+
"rules": [
|
|
1063
|
+
{
|
|
1064
|
+
"from": "LLM_API_KEY",
|
|
1065
|
+
"to": "PI_API_KEY"
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
"from": "LLM_BASE_URL",
|
|
1069
|
+
"to": "PI_BASE_URL"
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
"from": "LLM_MODEL",
|
|
1073
|
+
"to": "PI_MODEL"
|
|
1074
|
+
}
|
|
1075
|
+
]
|
|
1076
|
+
}
|
|
933
1077
|
}
|
|
934
1078
|
]
|
package/src/adapters/index.js
CHANGED
|
@@ -20,6 +20,7 @@ const CopilotAdapter = require('./copilot');
|
|
|
20
20
|
const ClineAdapter = require('./cline');
|
|
21
21
|
const AmpAdapter = require('./amp');
|
|
22
22
|
const MiniSweAgentAdapter = require('./mini');
|
|
23
|
+
const PiAdapter = require('./pi');
|
|
23
24
|
|
|
24
25
|
const ADAPTER_MAP = {
|
|
25
26
|
openclaw: OpenClawAdapter,
|
|
@@ -37,11 +38,12 @@ const ADAPTER_MAP = {
|
|
|
37
38
|
cline: ClineAdapter,
|
|
38
39
|
amp: AmpAdapter,
|
|
39
40
|
'mini-swe-agent': MiniSweAgentAdapter,
|
|
41
|
+
pi: PiAdapter,
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
45
|
* Create an adapter instance for the given agent type.
|
|
44
|
-
* @param {string} type - Agent type (openclaw, claude, codex, opencode, nanoclaw, cursor, hermes, gemini, kimi, aider, goose, copilot, cline, amp, mini-swe-agent)
|
|
46
|
+
* @param {string} type - Agent type (openclaw, claude, codex, opencode, nanoclaw, cursor, hermes, gemini, kimi, aider, goose, copilot, cline, amp, mini-swe-agent, pi)
|
|
45
47
|
* @param {object} opts - Adapter constructor options
|
|
46
48
|
* @returns {BaseAdapter}
|
|
47
49
|
*/
|
|
@@ -70,6 +72,7 @@ module.exports = {
|
|
|
70
72
|
ClineAdapter,
|
|
71
73
|
AmpAdapter,
|
|
72
74
|
MiniSweAgentAdapter,
|
|
75
|
+
PiAdapter,
|
|
73
76
|
createAdapter,
|
|
74
77
|
ADAPTER_MAP,
|
|
75
78
|
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local Pi provider configured entirely by Launcher environment fields.
|
|
3
|
+
*
|
|
4
|
+
* This extension is loaded explicitly when PI_BASE_URL or the Launcher's
|
|
5
|
+
* provider-neutral PI_API_KEY is set. It never persists settings or
|
|
6
|
+
* credentials: the key is read from the child environment at runtime. That
|
|
7
|
+
* keeps separate OpenAgents Pi instances isolated and leaves the user's
|
|
8
|
+
* ~/.pi/agent/models.json and auth.json untouched.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const value = (name) => String(process.env[name] || '').trim()
|
|
12
|
+
|
|
13
|
+
const PROVIDER_DEFAULTS = {
|
|
14
|
+
anthropic: {
|
|
15
|
+
baseUrl: 'https://api.anthropic.com',
|
|
16
|
+
api: 'anthropic-messages',
|
|
17
|
+
},
|
|
18
|
+
openai: {
|
|
19
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
20
|
+
api: 'openai-responses',
|
|
21
|
+
},
|
|
22
|
+
deepseek: {
|
|
23
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
24
|
+
api: 'openai-completions',
|
|
25
|
+
},
|
|
26
|
+
google: {
|
|
27
|
+
baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
|
|
28
|
+
api: 'google-generative-ai',
|
|
29
|
+
},
|
|
30
|
+
openrouter: {
|
|
31
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
32
|
+
api: 'openai-completions',
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function providerKey(provider) {
|
|
37
|
+
return value('PI_API_KEY') || {
|
|
38
|
+
anthropic: value('ANTHROPIC_API_KEY'),
|
|
39
|
+
openai: value('OPENAI_API_KEY'),
|
|
40
|
+
deepseek: value('DEEPSEEK_API_KEY'),
|
|
41
|
+
google: value('GEMINI_API_KEY'),
|
|
42
|
+
openrouter: value('OPENROUTER_API_KEY'),
|
|
43
|
+
}[provider] || ''
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function apiFormat(provider) {
|
|
47
|
+
const configured = value('PI_API_FORMAT').toLowerCase()
|
|
48
|
+
if (configured && configured !== 'auto') return configured
|
|
49
|
+
return PROVIDER_DEFAULTS[provider]?.api || 'openai-completions'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isOfficialAnthropic(url) {
|
|
53
|
+
try {
|
|
54
|
+
const host = new URL(url).hostname.toLowerCase()
|
|
55
|
+
return host === 'anthropic.com' || host.endsWith('.anthropic.com')
|
|
56
|
+
} catch {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default function configureLauncherProvider(pi) {
|
|
62
|
+
const provider = value('PI_PROVIDER').toLowerCase()
|
|
63
|
+
const model = value('PI_MODEL')
|
|
64
|
+
const key = providerKey(provider)
|
|
65
|
+
const configuredBaseUrl = value('PI_BASE_URL')
|
|
66
|
+
let baseUrl = (
|
|
67
|
+
configuredBaseUrl || PROVIDER_DEFAULTS[provider]?.baseUrl || ''
|
|
68
|
+
).replace(/\/+$/, '')
|
|
69
|
+
if (!baseUrl || !provider || !model || (!configuredBaseUrl && !key)) return
|
|
70
|
+
|
|
71
|
+
const api = apiFormat(provider)
|
|
72
|
+
// Anthropic's SDK appends /v1/messages itself. Accept either the service
|
|
73
|
+
// root or the commonly copied .../v1 URL from a relay dashboard.
|
|
74
|
+
if (api === 'anthropic-messages') baseUrl = baseUrl.replace(/\/v1$/i, '')
|
|
75
|
+
const thinking = value('PI_THINKING').toLowerCase()
|
|
76
|
+
const compat = {}
|
|
77
|
+
if (provider === 'deepseek' || baseUrl.toLowerCase().includes('deepseek.com')) {
|
|
78
|
+
compat.supportsDeveloperRole = false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pi.registerProvider(provider, {
|
|
82
|
+
baseUrl,
|
|
83
|
+
api,
|
|
84
|
+
// Pass the resolved secret directly to the process-local provider. This is
|
|
85
|
+
// deliberately not an argv flag or a persisted models.json/auth.json value.
|
|
86
|
+
// It also avoids relying on Pi's built-in credential resolver, which has
|
|
87
|
+
// failed to observe a present DEEPSEEK_API_KEY in some RPC launches.
|
|
88
|
+
apiKey: key || undefined,
|
|
89
|
+
// Anthropic's native endpoint uses x-api-key. The common relay convention
|
|
90
|
+
// is Bearer auth; enabling it for non-official endpoints mirrors the
|
|
91
|
+
// Launcher's Claude-agent behavior while leaving direct Anthropic untouched.
|
|
92
|
+
authHeader: api === 'anthropic-messages' && !isOfficialAnthropic(baseUrl),
|
|
93
|
+
...(Object.keys(compat).length ? { compat } : {}),
|
|
94
|
+
models: [
|
|
95
|
+
{
|
|
96
|
+
id: model,
|
|
97
|
+
name: model,
|
|
98
|
+
reasoning: !!thinking && thinking !== 'off',
|
|
99
|
+
input: ['text', 'image'],
|
|
100
|
+
// Pi's runtime cost calculator treats `cost` as required and reads its
|
|
101
|
+
// tier list after every provider response. Launcher-managed relays can
|
|
102
|
+
// have arbitrary pricing, so use an explicit zero-cost placeholder
|
|
103
|
+
// instead of inventing charges. The provider still bills normally.
|
|
104
|
+
cost: {
|
|
105
|
+
input: 0,
|
|
106
|
+
output: 0,
|
|
107
|
+
cacheRead: 0,
|
|
108
|
+
cacheWrite: 0,
|
|
109
|
+
tiers: [],
|
|
110
|
+
},
|
|
111
|
+
contextWindow: 200000,
|
|
112
|
+
maxTokens: 16384,
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
})
|
|
116
|
+
}
|