@openagents-org/agent-launcher 0.2.176 → 0.2.178
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/codebuddy.svg +38 -0
- package/icons/openworker.svg +3 -0
- package/package.json +1 -1
- package/registry.json +269 -0
- package/src/adapters/base.js +19 -0
- package/src/adapters/claude.js +36 -5
- package/src/adapters/codebuddy-stream.js +497 -0
- package/src/adapters/codebuddy.js +913 -0
- package/src/adapters/codex.js +2 -12
- package/src/adapters/index.js +6 -1
- package/src/adapters/opencode.js +2 -13
- package/src/adapters/openworker-runtime.js +572 -0
- package/src/adapters/openworker.js +921 -0
- package/src/adapters/utils.js +27 -0
- package/src/adapters/workspace-prompt.js +33 -0
- package/src/install-preflight.js +84 -6
- package/src/installer.js +16 -0
- package/src/paths.js +20 -8
- package/src/probe.js +53 -4
- package/src/utils.js +24 -5
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 40 40" fill="none" role="img" style="flex:none;line-height:1">
|
|
2
|
+
<title>CodeBuddy Code</title>
|
|
3
|
+
<g clip-path="url(#cb-clip)">
|
|
4
|
+
<rect width="40" height="40" rx="20" fill="url(#cb-bg)"/>
|
|
5
|
+
<g filter="url(#cb-glow-a)">
|
|
6
|
+
<circle cx="12.6071" cy="34.9794" r="14.081" fill="#32E6B9" fill-opacity="0.4"/>
|
|
7
|
+
</g>
|
|
8
|
+
<g filter="url(#cb-glow-b)">
|
|
9
|
+
<circle cx="33.3404" cy="43.6185" r="12.8704" fill="#32E6B9"/>
|
|
10
|
+
</g>
|
|
11
|
+
<path d="M27.6897 3.3426C28.057 3.01322 28.0795 2.99983 28.3485 2.98366C28.7851 2.95177 29.1858 3.16107 29.8664 3.78072C31.4566 5.22574 33.6703 8.19724 35.047 10.7343L35.5796 11.7191L36.3309 12.0927C37.0562 12.4593 38.2459 13.2111 38.7428 13.614C38.9673 13.7997 38.9992 13.8032 39.2326 13.7124C40.2872 13.3017 41.7982 13.846 43.1307 15.1244C44.3302 16.274 45.479 18.2384 45.9191 19.8778C45.9833 20.1417 46.0683 20.709 46.0994 21.1314C46.1997 22.6144 45.7243 23.7986 44.8085 24.3349C44.6213 24.443 44.6085 24.4725 44.6137 24.939C44.6559 27.1604 44.0571 29.3777 42.8543 31.54C41.4965 33.9678 39.0794 36.4798 35.8073 38.846C34.0502 40.1247 29.8918 42.5469 28.0122 43.3973C23.5096 45.4244 19.8999 46.2022 16.7645 45.8181C14.8943 45.5915 12.7771 44.8611 11.5246 44.0137C11.1951 43.786 11.1428 43.7719 10.8909 43.8439C9.55017 44.2289 7.79442 43.4374 6.30272 41.7817C5.70771 41.1197 4.74709 39.4939 4.43575 38.6241C3.71569 36.5887 3.85859 34.752 4.81783 33.6551C5.0657 33.3725 5.07387 33.3607 5.01972 32.8856C4.93033 32.1079 4.88982 30.9566 4.93066 30.2138L4.96343 29.5205L3.92091 27.6777C2.3078 24.8074 1.28326 22.3968 0.887982 20.5554C0.679402 19.546 0.692781 19.0981 0.949061 18.7667C1.10529 18.5666 1.61622 18.3594 2.23252 18.2455C3.78518 17.9729 7.17203 18.2198 10.9394 18.885L11.3303 18.9525L12.1903 18.1921C13.6179 16.9275 14.5665 16.2176 16.315 15.1274C18.1373 13.9872 20.1943 13.0498 22.5103 12.3071L23.2533 12.0687L23.6615 10.9964C25.1239 7.13587 26.6218 4.28969 27.6897 3.3426ZM15.4393 23.1261C13.7864 24.0804 12.9602 24.5582 12.3529 25.093C9.89364 27.2585 8.9738 30.6888 10.0208 33.7938C10.2794 34.5606 10.7568 35.387 11.7111 37.0398C12.6653 38.6926 13.1424 39.5194 13.6771 40.1267C15.8426 42.5859 19.2732 43.5045 22.3783 42.4574C23.145 42.1989 23.972 41.7223 25.6248 40.768L35.1333 35.2783C36.7862 34.324 37.6124 33.8462 38.2196 33.3114C40.6789 31.1459 41.5988 27.7156 40.5518 24.6105C40.2932 23.8438 39.8157 23.0174 38.8615 21.3646C37.9072 19.7117 37.4302 18.885 36.8955 18.2777C34.7299 15.8185 31.2993 14.8999 28.1943 15.947C27.4275 16.2055 26.6006 16.6821 24.9478 17.6364L15.4393 23.1261Z" fill="url(#cb-cat)"/>
|
|
12
|
+
<rect x="15.8816" y="30.0273" width="4.00904" height="8.32646" rx="2.00452" transform="rotate(-30 15.8816 30.0273)" fill="white"/>
|
|
13
|
+
<rect x="26.6978" y="23.7812" width="4.00904" height="8.32646" rx="2.00452" transform="rotate(-30 26.6978 23.7812)" fill="white"/>
|
|
14
|
+
</g>
|
|
15
|
+
<defs>
|
|
16
|
+
<filter id="cb-glow-a" x="-14.9163" y="7.45599" width="55.0468" height="55.047" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
|
17
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
|
18
|
+
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
|
19
|
+
<feGaussianBlur stdDeviation="6.72123" result="cb-blur"/>
|
|
20
|
+
</filter>
|
|
21
|
+
<filter id="cb-glow-b" x="9.46959" y="19.7477" width="47.7417" height="47.741" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
|
22
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
|
23
|
+
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
|
24
|
+
<feGaussianBlur stdDeviation="5.50019" result="cb-blur"/>
|
|
25
|
+
</filter>
|
|
26
|
+
<linearGradient id="cb-bg" x1="20" y1="0" x2="20" y2="40" gradientUnits="userSpaceOnUse">
|
|
27
|
+
<stop stop-color="#6C4DFF"/>
|
|
28
|
+
<stop offset="1" stop-color="#583ED3"/>
|
|
29
|
+
</linearGradient>
|
|
30
|
+
<linearGradient id="cb-cat" x1="14.639" y1="10.7917" x2="32.1712" y2="41.1585" gradientUnits="userSpaceOnUse">
|
|
31
|
+
<stop stop-color="white" stop-opacity="0.8"/>
|
|
32
|
+
<stop offset="0.437689" stop-color="white"/>
|
|
33
|
+
</linearGradient>
|
|
34
|
+
<clipPath id="cb-clip">
|
|
35
|
+
<rect width="40" height="40" rx="20" fill="white"/>
|
|
36
|
+
</clipPath>
|
|
37
|
+
</defs>
|
|
38
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024" role="img" style="flex:none;line-height:1">
|
|
2
|
+
<title>OpenWorker</title>
|
|
3
|
+
<rect x="88" y="88" width="848" height="848" rx="182" fill="#2563eb"/><path d="M257.5 512A843.7 843.7 0 0 1 766.5 512A843.7 843.7 0 0 1 257.5 512ZM384.75 291.6A843.7 843.7 0 0 1 639.25 732.4A843.7 843.7 0 0 1 384.75 291.6ZM639.25 291.6A843.7 843.7 0 0 1 384.75 732.4A843.7 843.7 0 0 1 639.25 291.6Z" fill="#fff"/></svg>
|
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -1437,5 +1437,274 @@
|
|
|
1437
1437
|
}
|
|
1438
1438
|
]
|
|
1439
1439
|
}
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
"name": "openworker",
|
|
1443
|
+
"label": "OpenWorker",
|
|
1444
|
+
"description": "Local-first agent coworker driven headlessly through its own server",
|
|
1445
|
+
"homepage": "https://openworker.com",
|
|
1446
|
+
"tags": [
|
|
1447
|
+
"coding",
|
|
1448
|
+
"local-first",
|
|
1449
|
+
"byom",
|
|
1450
|
+
"open-source"
|
|
1451
|
+
],
|
|
1452
|
+
"builtin": true,
|
|
1453
|
+
"support": {
|
|
1454
|
+
"install": true,
|
|
1455
|
+
"workspace": true,
|
|
1456
|
+
"collaboration": true
|
|
1457
|
+
},
|
|
1458
|
+
"install": {
|
|
1459
|
+
"binary": "openworker-server",
|
|
1460
|
+
"binary_aliases": [
|
|
1461
|
+
"openworker",
|
|
1462
|
+
"ocw"
|
|
1463
|
+
],
|
|
1464
|
+
"requires": [
|
|
1465
|
+
"git",
|
|
1466
|
+
"uv"
|
|
1467
|
+
],
|
|
1468
|
+
"verify": "openworker-server --help",
|
|
1469
|
+
"verify_win": "openworker-server --help",
|
|
1470
|
+
"macos": "uv tool install git+https://github.com/andrewyng/openworker",
|
|
1471
|
+
"linux": "uv tool install git+https://github.com/andrewyng/openworker",
|
|
1472
|
+
"windows": "uv tool install git+https://github.com/andrewyng/openworker"
|
|
1473
|
+
},
|
|
1474
|
+
"adapter": {
|
|
1475
|
+
"module": "openagents.adapters.openworker",
|
|
1476
|
+
"class": "OpenWorkerAdapter"
|
|
1477
|
+
},
|
|
1478
|
+
"launch": null,
|
|
1479
|
+
"env_config": [
|
|
1480
|
+
{
|
|
1481
|
+
"name": "OPENWORKER_PROVIDER",
|
|
1482
|
+
"description": "Which model provider the API key belongs to. OpenWorker is bring-your-own-model, so this decides both the endpoint and how the model id is routed. Use ollama for a local server, or openai-codex to reuse a ChatGPT subscription (which also needs OPENWORKER_STATE_DIR).",
|
|
1483
|
+
"required": false,
|
|
1484
|
+
"default": "openai",
|
|
1485
|
+
"options": [
|
|
1486
|
+
"openai",
|
|
1487
|
+
"anthropic",
|
|
1488
|
+
"gemini",
|
|
1489
|
+
"deepseek",
|
|
1490
|
+
"kimi",
|
|
1491
|
+
"qwen",
|
|
1492
|
+
"minimax",
|
|
1493
|
+
"xai",
|
|
1494
|
+
"mistral",
|
|
1495
|
+
"together",
|
|
1496
|
+
"fireworks",
|
|
1497
|
+
"openrouter",
|
|
1498
|
+
"zai",
|
|
1499
|
+
"ark",
|
|
1500
|
+
"meta",
|
|
1501
|
+
"ollama",
|
|
1502
|
+
"openai-codex"
|
|
1503
|
+
]
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
"name": "OPENWORKER_API_KEY",
|
|
1507
|
+
"description": "API key for the provider selected above. Passed to the OpenWorker server in its environment and never written to disk. Leave blank only for ollama, or when reusing a state directory that already holds credentials.",
|
|
1508
|
+
"required": false,
|
|
1509
|
+
"password": true
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
"name": "OPENWORKER_BASE_URL",
|
|
1513
|
+
"description": "Endpoint override — for a relay, a self-hosted gateway, Azure OpenAI, or where `ollama serve` is listening. Leave blank to use the provider's official endpoint.",
|
|
1514
|
+
"required": false,
|
|
1515
|
+
"placeholder": "https://my-endpoint.example/v1"
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
"name": "OPENWORKER_MODEL",
|
|
1519
|
+
"description": "Model id to run on. Leave empty for the OpenWorker default; the provider prefix is added automatically, so plain `claude-opus-5` is enough when the provider is anthropic.",
|
|
1520
|
+
"required": false,
|
|
1521
|
+
"placeholder": "gpt-5.6-sol"
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
"name": "OPENWORKER_MODE",
|
|
1525
|
+
"description": "Permission mode for each turn. `bypass-approvals` is the default because nobody is at the keyboard to approve tool calls; its hard floors (settings files, writes outside the workspace, .git/hooks) still apply. `interactive` and `auto-approve` will stall on anything that asks.",
|
|
1526
|
+
"required": false,
|
|
1527
|
+
"default": "bypass-approvals",
|
|
1528
|
+
"options": [
|
|
1529
|
+
"bypass-approvals",
|
|
1530
|
+
"auto-approve",
|
|
1531
|
+
"interactive",
|
|
1532
|
+
"plan"
|
|
1533
|
+
]
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
"name": "OPENWORKER_ALLOW_TOOL_INSTALL",
|
|
1537
|
+
"description": "Set to 1 to let the agent install tools from OpenWorker's pinned catalog on its own. Off by default — a declined request is a supported outcome and the agent falls back and says so.",
|
|
1538
|
+
"required": false,
|
|
1539
|
+
"default": "0",
|
|
1540
|
+
"options": [
|
|
1541
|
+
"0",
|
|
1542
|
+
"1"
|
|
1543
|
+
]
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
"name": "OPENWORKER_STATE_DIR",
|
|
1547
|
+
"description": "Advanced. Where the OpenWorker server keeps its conversations and credentials. Blank means a private directory under ~/.openagents. Point it at the desktop app's state directory (~/.config/coworker, or %APPDATA%\\coworker) to reuse its sign-ins — but only while that app is closed, since two processes must never write one store.",
|
|
1548
|
+
"required": false,
|
|
1549
|
+
"placeholder": "~/.config/coworker"
|
|
1550
|
+
}
|
|
1551
|
+
],
|
|
1552
|
+
"check_ready": {
|
|
1553
|
+
"env_vars": [
|
|
1554
|
+
"OPENWORKER_API_KEY",
|
|
1555
|
+
"OPENAI_API_KEY",
|
|
1556
|
+
"ANTHROPIC_API_KEY",
|
|
1557
|
+
"GEMINI_API_KEY"
|
|
1558
|
+
],
|
|
1559
|
+
"saved_env_key": "OPENWORKER_API_KEY",
|
|
1560
|
+
"not_ready_message": "No model API key — pick a provider and set OPENWORKER_API_KEY (press e to configure)",
|
|
1561
|
+
"unreadable_message": "The OpenWorker model key could not be read. Re-enter OPENWORKER_API_KEY in the Configure screen."
|
|
1562
|
+
},
|
|
1563
|
+
"resolve_env": {
|
|
1564
|
+
"rules": [
|
|
1565
|
+
{
|
|
1566
|
+
"from": "LLM_API_KEY",
|
|
1567
|
+
"to": "OPENWORKER_API_KEY"
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
"from": "LLM_MODEL",
|
|
1571
|
+
"to": "OPENWORKER_MODEL"
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
"from": "LLM_BASE_URL",
|
|
1575
|
+
"to": "OPENWORKER_BASE_URL"
|
|
1576
|
+
}
|
|
1577
|
+
]
|
|
1578
|
+
}
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
"name": "codebuddy",
|
|
1582
|
+
"label": "CodeBuddy Code",
|
|
1583
|
+
"description": "Tencent's CodeBuddy Code CLI — the same engine the WorkBuddy desktop app runs, driven headlessly",
|
|
1584
|
+
"homepage": "https://www.codebuddy.ai",
|
|
1585
|
+
"tags": [
|
|
1586
|
+
"workbuddy",
|
|
1587
|
+
"coding",
|
|
1588
|
+
"cli",
|
|
1589
|
+
"tencent",
|
|
1590
|
+
"headless"
|
|
1591
|
+
],
|
|
1592
|
+
"builtin": true,
|
|
1593
|
+
"support": {
|
|
1594
|
+
"install": true,
|
|
1595
|
+
"workspace": true,
|
|
1596
|
+
"collaboration": true
|
|
1597
|
+
},
|
|
1598
|
+
"install": {
|
|
1599
|
+
"binary": "codebuddy",
|
|
1600
|
+
"binary_aliases": [
|
|
1601
|
+
"codebuddy-code",
|
|
1602
|
+
"cbc"
|
|
1603
|
+
],
|
|
1604
|
+
"npm_package": "@tencent-ai/codebuddy-code",
|
|
1605
|
+
"requires": [
|
|
1606
|
+
"nodejs"
|
|
1607
|
+
],
|
|
1608
|
+
"verify": "codebuddy --version",
|
|
1609
|
+
"verify_win": "codebuddy --version",
|
|
1610
|
+
"macos": "npm install -g @tencent-ai/codebuddy-code",
|
|
1611
|
+
"linux": "npm install -g @tencent-ai/codebuddy-code",
|
|
1612
|
+
"windows": "npm install -g @tencent-ai/codebuddy-code"
|
|
1613
|
+
},
|
|
1614
|
+
"adapter": {
|
|
1615
|
+
"module": "openagents.adapters.codebuddy",
|
|
1616
|
+
"class": "CodeBuddyAdapter"
|
|
1617
|
+
},
|
|
1618
|
+
"launch": null,
|
|
1619
|
+
"env_config": [
|
|
1620
|
+
{
|
|
1621
|
+
"name": "CODEBUDDY_REGION",
|
|
1622
|
+
"description": "Which CodeBuddy site the account belongs to. `international` is codebuddy.ai / workbuddy.ai (Google or GitHub sign-in); `china` is codebuddy.cn / workbuddy.cn. An account only exists on one of them, and picking the wrong one fails as a login error rather than a routing error.",
|
|
1623
|
+
"required": false,
|
|
1624
|
+
"default": "international",
|
|
1625
|
+
"options": [
|
|
1626
|
+
"international",
|
|
1627
|
+
"china"
|
|
1628
|
+
]
|
|
1629
|
+
},
|
|
1630
|
+
{
|
|
1631
|
+
"name": "CODEBUDDY_API_KEY",
|
|
1632
|
+
"description": "CodeBuddy API key, for running without an interactive sign-in. Optional — leave blank if you signed in by running `codebuddy` and using /login on this machine.",
|
|
1633
|
+
"required": false,
|
|
1634
|
+
"password": true
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
"name": "CODEBUDDY_AUTH_TOKEN",
|
|
1638
|
+
"description": "Platform auth token, the alternative to an API key (an enterprise PAT, for example). Paste the token itself; a leading `Bearer ` is stripped for you.",
|
|
1639
|
+
"required": false,
|
|
1640
|
+
"password": true
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
"name": "CODEBUDDY_MODEL",
|
|
1644
|
+
"description": "Model id to run on. Leave empty for the account default. The CLI also accepts its aliases — default-model, fast-model, deep-model — which keep working when the underlying model is replaced.",
|
|
1645
|
+
"required": false,
|
|
1646
|
+
"placeholder": "default-model"
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
"name": "CODEBUDDY_EFFORT",
|
|
1650
|
+
"description": "Reasoning effort for each run. Leave empty for the model's own default.",
|
|
1651
|
+
"required": false,
|
|
1652
|
+
"options": [
|
|
1653
|
+
"minimal",
|
|
1654
|
+
"low",
|
|
1655
|
+
"medium",
|
|
1656
|
+
"high",
|
|
1657
|
+
"xhigh",
|
|
1658
|
+
"max"
|
|
1659
|
+
]
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
"name": "CODEBUDDY_MAX_TURNS",
|
|
1663
|
+
"description": "Maximum agentic turns per message. Leave empty for the CLI default; a run that hits the limit still returns the answer it reached.",
|
|
1664
|
+
"required": false,
|
|
1665
|
+
"placeholder": "100"
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
"name": "CODEBUDDY_BASE_URL",
|
|
1669
|
+
"description": "Advanced. Endpoint override, for an enterprise or self-hosted deployment. Blank means the endpoint the region above selects.",
|
|
1670
|
+
"required": false,
|
|
1671
|
+
"placeholder": "https://www.codebuddy.cn"
|
|
1672
|
+
}
|
|
1673
|
+
],
|
|
1674
|
+
"check_ready": {
|
|
1675
|
+
"min_version": "2.0.0",
|
|
1676
|
+
"env_vars": [
|
|
1677
|
+
"CODEBUDDY_API_KEY",
|
|
1678
|
+
"CODEBUDDY_AUTH_TOKEN"
|
|
1679
|
+
],
|
|
1680
|
+
"saved_env_key": "CODEBUDDY_API_KEY",
|
|
1681
|
+
"login_command": "codebuddy",
|
|
1682
|
+
"unverifiable": true,
|
|
1683
|
+
"not_ready_message": "Not signed in for this site. Sign in with the Login button — it opens the CLI on the site CODEBUDDY_REGION selects, where you run /login — or set CODEBUDDY_API_KEY / CODEBUDDY_AUTH_TOKEN (press e). A session for the other site does not carry over: the CLI keeps only one, and codebuddy.ai and codebuddy.cn are separate accounts.",
|
|
1684
|
+
"auth_detected_labels": {
|
|
1685
|
+
"cli_login": "CodeBuddy sign-in detected",
|
|
1686
|
+
"api_key": "API key detected"
|
|
1687
|
+
},
|
|
1688
|
+
"alt_check": "codebuddy -p hi"
|
|
1689
|
+
},
|
|
1690
|
+
"probe": {
|
|
1691
|
+
"args": [
|
|
1692
|
+
"-p",
|
|
1693
|
+
"hi"
|
|
1694
|
+
],
|
|
1695
|
+
"timeout_s": 120
|
|
1696
|
+
},
|
|
1697
|
+
"resolve_env": {
|
|
1698
|
+
"rules": [
|
|
1699
|
+
{
|
|
1700
|
+
"from": "LLM_API_KEY",
|
|
1701
|
+
"to": "CODEBUDDY_API_KEY"
|
|
1702
|
+
},
|
|
1703
|
+
{
|
|
1704
|
+
"from": "LLM_MODEL",
|
|
1705
|
+
"to": "CODEBUDDY_MODEL"
|
|
1706
|
+
}
|
|
1707
|
+
]
|
|
1708
|
+
}
|
|
1440
1709
|
}
|
|
1441
1710
|
]
|
package/src/adapters/base.js
CHANGED
|
@@ -1079,11 +1079,23 @@ class BaseAdapter {
|
|
|
1079
1079
|
}
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
|
+
/**
|
|
1083
|
+
* Post the agent's answer for a turn — the last thing said before control
|
|
1084
|
+
* returns to the user.
|
|
1085
|
+
*
|
|
1086
|
+
* `status_kind: 'completed'` marks it as exactly that. The backend's push
|
|
1087
|
+
* fan-out (workspace/backend/app/services/push.py) reads the field and
|
|
1088
|
+
* notifies under the user's "task completions" switch instead of the
|
|
1089
|
+
* "all messages" firehose, which is off by default. It has to be a
|
|
1090
|
+
* structured field: an earlier attempt matched the word "completed" in the
|
|
1091
|
+
* message text and fired on every bash for-loop that ended in `done`.
|
|
1092
|
+
*/
|
|
1082
1093
|
async sendResponse(channel, content) {
|
|
1083
1094
|
try {
|
|
1084
1095
|
await this.client.sendMessage(this.workspaceId, channel, this.token, content, {
|
|
1085
1096
|
senderType: 'agent',
|
|
1086
1097
|
senderName: this.agentName,
|
|
1098
|
+
metadata: { status_kind: 'completed' },
|
|
1087
1099
|
sessionId: this._sessionId,
|
|
1088
1100
|
});
|
|
1089
1101
|
} catch (e) {
|
|
@@ -1154,11 +1166,18 @@ class BaseAdapter {
|
|
|
1154
1166
|
}
|
|
1155
1167
|
}
|
|
1156
1168
|
|
|
1169
|
+
/**
|
|
1170
|
+
* Post a turn that ended badly. Carries `status_kind: 'error'` so the push
|
|
1171
|
+
* fan-out routes it to the user's "agent errors" switch rather than the
|
|
1172
|
+
* general message firehose — same structured-field contract as
|
|
1173
|
+
* sendResponse's 'completed'.
|
|
1174
|
+
*/
|
|
1157
1175
|
async sendError(channel, error) {
|
|
1158
1176
|
try {
|
|
1159
1177
|
await this.client.sendMessage(this.workspaceId, channel, this.token, error, {
|
|
1160
1178
|
senderType: 'agent',
|
|
1161
1179
|
senderName: this.agentName,
|
|
1180
|
+
metadata: { status_kind: 'error' },
|
|
1162
1181
|
sessionId: this._sessionId,
|
|
1163
1182
|
});
|
|
1164
1183
|
} catch (e) {
|
package/src/adapters/claude.js
CHANGED
|
@@ -17,7 +17,7 @@ const path = require('path');
|
|
|
17
17
|
const { execSync, spawn } = require('child_process');
|
|
18
18
|
|
|
19
19
|
const BaseAdapter = require('./base');
|
|
20
|
-
const { formatAttachmentsForPrompt, SESSION_DEFAULT_RE, generateSessionTitle } = require('./utils');
|
|
20
|
+
const { formatAttachmentsForPrompt, SESSION_DEFAULT_RE, generateSessionTitle, redactSecrets } = require('./utils');
|
|
21
21
|
const { buildClaudeSystemPrompt, buildClaudeSkillMd, workspaceSkillName } = require('./workspace-prompt');
|
|
22
22
|
const { pinnedFingerprint, sampleRecap } = require('./decision-log');
|
|
23
23
|
const { defaultAgentWorkdir, whichBinary, whereBinary } = require('../paths');
|
|
@@ -737,9 +737,17 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
737
737
|
}
|
|
738
738
|
|
|
739
739
|
if (consecutiveTimeouts >= this._WATCHDOG_MAX_TIMEOUTS) {
|
|
740
|
+
const tail = this._stderrTail(pp);
|
|
740
741
|
this._log(`Watchdog: process unresponsive for ${consecutiveTimeouts * 15}s on ${pp.msgChannel} — killing`);
|
|
742
|
+
if (tail) this._log(`stderr: ${tail}`);
|
|
741
743
|
this._stopWatchdog(pp);
|
|
742
|
-
try {
|
|
744
|
+
try {
|
|
745
|
+
await this.sendError(
|
|
746
|
+
pp.msgChannel,
|
|
747
|
+
'Agent process became unresponsive and was restarted.' +
|
|
748
|
+
(tail ? `\n\n\`\`\`\n${tail}\n\`\`\`` : ''),
|
|
749
|
+
);
|
|
750
|
+
} catch {}
|
|
743
751
|
if (pp.messageResolve) {
|
|
744
752
|
const resolve = pp.messageResolve;
|
|
745
753
|
pp.messageResolve = null;
|
|
@@ -926,6 +934,8 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
926
934
|
|
|
927
935
|
proc.on('exit', (code) => {
|
|
928
936
|
this._log(`Persistent process exited: channel=${channel} code=${code}`);
|
|
937
|
+
const tail = this._stderrTail(pp);
|
|
938
|
+
if (tail) this._log(`stderr: ${tail}`);
|
|
929
939
|
pp.alive = false;
|
|
930
940
|
if (pp.idleTimer) clearTimeout(pp.idleTimer);
|
|
931
941
|
this._stopWatchdog(pp);
|
|
@@ -992,6 +1002,22 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
992
1002
|
});
|
|
993
1003
|
}
|
|
994
1004
|
|
|
1005
|
+
/**
|
|
1006
|
+
* What the CLI wrote to stderr this turn, trimmed and redacted, or ''.
|
|
1007
|
+
*
|
|
1008
|
+
* `stderrBuf` was collected and then read by nothing at all: when the process
|
|
1009
|
+
* died before emitting a single JSON event, or hung without emitting one, the
|
|
1010
|
+
* only account of why sat in a string no code path ever looked at. The channel
|
|
1011
|
+
* got "No response generated" and the daemon log got an exit code, so a run
|
|
1012
|
+
* that had the reason in hand reported none. codex, gemini and opencode all
|
|
1013
|
+
* log their stderr on exit; this is that, plus the two paths — watchdog kill
|
|
1014
|
+
* and silent exit — where it is the ONLY thing there is to report.
|
|
1015
|
+
*/
|
|
1016
|
+
_stderrTail(pp) {
|
|
1017
|
+
const tail = String((pp && pp.stderrBuf) || '').trim();
|
|
1018
|
+
return tail ? redactSecrets(tail).slice(-800) : '';
|
|
1019
|
+
}
|
|
1020
|
+
|
|
995
1021
|
/**
|
|
996
1022
|
* Turn a raw Claude `result` error into a user-facing message. Auth failures
|
|
997
1023
|
* (401 / invalid token) are the most common real-world cause and are otherwise
|
|
@@ -1291,10 +1317,15 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
1291
1317
|
continue;
|
|
1292
1318
|
}
|
|
1293
1319
|
if (!pp.everPostedAnything) {
|
|
1294
|
-
|
|
1295
|
-
|
|
1320
|
+
// stderr is the fallback, not nothing: a CLI that dies before its
|
|
1321
|
+
// first JSON event leaves no `result` to read, and "No response
|
|
1322
|
+
// generated. Please try again." is what turned those into an
|
|
1323
|
+
// unreportable failure.
|
|
1324
|
+
const detail = pp.lastErrorText || this._stderrTail(pp);
|
|
1325
|
+
if (detail) {
|
|
1326
|
+
try { await this.sendError(msgChannel, this._formatClaudeError(detail)); } catch {}
|
|
1296
1327
|
} else {
|
|
1297
|
-
try { await this.sendResponse(msgChannel,
|
|
1328
|
+
try { await this.sendResponse(msgChannel, `No response generated (exit code ${result.code === undefined ? 'unknown' : result.code}). Please try again.`); } catch {}
|
|
1298
1329
|
}
|
|
1299
1330
|
}
|
|
1300
1331
|
break;
|