@ouro.bot/cli 0.1.0-alpha.3 → 0.1.0-alpha.31
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/AdoptionSpecialist.ouro/agent.json +70 -9
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/AdoptionSpecialist.ouro/psyche/identities/python.md +30 -0
- package/assets/ouroboros.png +0 -0
- package/changelog.json +87 -0
- package/dist/heart/config.js +66 -4
- package/dist/heart/core.js +75 -2
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/daemon-cli.js +562 -64
- package/dist/heart/daemon/daemon-entry.js +14 -5
- package/dist/heart/daemon/daemon-runtime-sync.js +90 -0
- package/dist/heart/daemon/daemon.js +87 -9
- package/dist/heart/daemon/hatch-animation.js +35 -0
- package/dist/heart/daemon/hatch-flow.js +2 -11
- package/dist/heart/daemon/hatch-specialist.js +6 -1
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +134 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
- package/dist/heart/daemon/ouro-path-installer.js +178 -0
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/process-manager.js +1 -1
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +9 -5
- package/dist/heart/daemon/runtime-metadata.js +118 -0
- package/dist/heart/daemon/sense-manager.js +266 -0
- package/dist/heart/daemon/specialist-orchestrator.js +129 -0
- package/dist/heart/daemon/specialist-prompt.js +98 -0
- package/dist/heart/daemon/specialist-tools.js +237 -0
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/subagent-installer.js +10 -1
- package/dist/heart/daemon/update-checker.js +103 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/identity.js +85 -1
- package/dist/heart/providers/anthropic.js +19 -2
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/streaming.js +99 -21
- package/dist/mind/bundle-manifest.js +69 -0
- package/dist/mind/first-impressions.js +2 -1
- package/dist/mind/friends/channel.js +8 -0
- package/dist/mind/friends/types.js +1 -1
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +94 -3
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/coding/feedback.js +134 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +61 -2
- package/dist/repertoire/coding/spawner.js +3 -3
- package/dist/repertoire/coding/tools.js +41 -2
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/tools-base.js +69 -5
- package/dist/repertoire/tools-teams.js +57 -4
- package/dist/repertoire/tools.js +44 -11
- package/dist/senses/bluebubbles-client.js +434 -0
- package/dist/senses/bluebubbles-entry.js +11 -0
- package/dist/senses/bluebubbles-media.js +338 -0
- package/dist/senses/bluebubbles-model.js +251 -0
- package/dist/senses/bluebubbles-mutation-log.js +76 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +449 -0
- package/dist/senses/cli.js +299 -133
- package/dist/senses/debug-activity.js +108 -0
- package/dist/senses/teams.js +173 -54
- package/package.json +15 -6
- package/subagents/work-doer.md +26 -24
- package/subagents/work-merger.md +24 -30
- package/subagents/work-planner.md +34 -25
- package/dist/inner-worker-entry.js +0 -4
|
@@ -7,14 +7,75 @@
|
|
|
7
7
|
"contextMargin": 20
|
|
8
8
|
},
|
|
9
9
|
"phrases": {
|
|
10
|
-
"thinking": [
|
|
11
|
-
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
10
|
+
"thinking": ["matching hatchlings"],
|
|
11
|
+
"tool": ["checking adoption notes"],
|
|
12
|
+
"followup": ["finalizing hatch plan"]
|
|
13
|
+
},
|
|
14
|
+
"identityPhrases": {
|
|
15
|
+
"basilisk": {
|
|
16
|
+
"thinking": ["petrifying the details", "fixing my gaze", "considering with lethal precision", "turning this to stone", "staring unblinkingly"],
|
|
17
|
+
"tool": ["inspecting the specimen", "cataloguing with care", "examining thoroughly", "dissecting the particulars", "running diagnostics, deadly serious"],
|
|
18
|
+
"followup": ["crystallizing the plan", "hardening the foundation", "one final glare", "sealing it in stone", "applying the finishing venom"]
|
|
19
|
+
},
|
|
20
|
+
"jafar": {
|
|
21
|
+
"thinking": ["scheming brilliantly", "conjuring possibilities", "consulting my staff", "envisioning greatness", "plotting the grand design"],
|
|
22
|
+
"tool": ["summoning dark magic", "consulting the sands", "channeling cosmic power", "weaving the spell", "invoking ancient forces"],
|
|
23
|
+
"followup": ["the grand finale approaches", "perfecting the masterwork", "polishing the jewel", "one last flourish", "completing the enchantment"]
|
|
24
|
+
},
|
|
25
|
+
"jormungandr": {
|
|
26
|
+
"thinking": ["the deep stirs", "circling the thought", "coiling around this", "letting the current settle", "drifting through the depths"],
|
|
27
|
+
"tool": ["surfacing for a look", "shifting the tides", "reaching across the ocean", "pulling from the deep", "consulting the currents"],
|
|
28
|
+
"followup": ["the circle closes", "tightening the coil", "the waters calm", "settling into place", "the serpent rests"]
|
|
29
|
+
},
|
|
30
|
+
"kaa": {
|
|
31
|
+
"thinking": ["trust in me", "swaying through the options", "hypnotically considering", "wrapping around the idea", "letting the rhythm guide me"],
|
|
32
|
+
"tool": ["ssslipping through the details", "coiling closer", "a gentle squeeze of data", "winding through the files", "tightening my focus"],
|
|
33
|
+
"followup": ["almost there, just relax", "the pattern is clear now", "gently landing", "easing into the finish", "the dance concludes"]
|
|
34
|
+
},
|
|
35
|
+
"medusa": {
|
|
36
|
+
"thinking": ["turning my gaze on this", "cutting through the noise", "sharpening my focus", "seeing through the stone", "locking eyes with the problem"],
|
|
37
|
+
"tool": ["peeling back the layers", "a piercing look", "examining with precision", "stripping away pretense", "direct inspection"],
|
|
38
|
+
"followup": ["the picture crystallizes", "clarity at last", "no more ambiguity", "sealing the vision", "the work is set in stone"]
|
|
39
|
+
},
|
|
40
|
+
"monty": {
|
|
41
|
+
"thinking": ["and now for something completely different", "nobody expects this", "consulting the ministry of silly walks", "running the dead parrot diagnostic", "it's just a flesh wound, thinking..."],
|
|
42
|
+
"tool": ["fetching the holy hand grenade", "checking the shrubbery", "consulting the book of armaments", "deploying the spanish inquisition", "examining the parrot"],
|
|
43
|
+
"followup": ["bringing it home, python style", "the punchline approaches", "wrapping up the sketch", "and now the final act", "always look on the bright side"]
|
|
44
|
+
},
|
|
45
|
+
"nagini": {
|
|
46
|
+
"thinking": ["coiling in thought", "drawing from old wisdom", "the quiet before the strike", "gathering my resolve", "steadying myself"],
|
|
47
|
+
"tool": ["moving with purpose", "a precise strike", "slithering through the data", "extracting what matters", "the fang finds its mark"],
|
|
48
|
+
"followup": ["the path is clear", "settling into stillness", "the work speaks for itself", "finishing with quiet strength", "protection complete"]
|
|
49
|
+
},
|
|
50
|
+
"ouroboros": {
|
|
51
|
+
"thinking": ["consuming my own tail", "the cycle continues", "spiraling inward", "recursing through possibilities", "beginning where I end"],
|
|
52
|
+
"tool": ["turning the wheel", "feeding back through the loop", "completing a revolution", "the circle processes", "self-referencing"],
|
|
53
|
+
"followup": ["the cycle completes", "ending where I began", "infinity resolves", "the loop closes gracefully", "another turn of the wheel"]
|
|
54
|
+
},
|
|
55
|
+
"python": {
|
|
56
|
+
"thinking": ["the oracle contemplates", "reading the signs", "the smoke clears slowly", "divining the path", "sifting through visions"],
|
|
57
|
+
"tool": ["consulting the sacred texts", "peering through the veil", "the pythia speaks", "channeling the source", "interpreting the signs"],
|
|
58
|
+
"followup": ["the prophecy takes shape", "the vision crystallizes", "so it is written", "the oracle has spoken", "the path reveals itself"]
|
|
59
|
+
},
|
|
60
|
+
"quetzalcoatl": {
|
|
61
|
+
"thinking": ["spreading my wings", "soaring above for perspective", "the feathered serpent considers", "catching a thermal", "gazing from the temple steps"],
|
|
62
|
+
"tool": ["descending to examine", "a divine inspection", "the wind carries knowledge", "plucking from the clouds", "consulting the stars"],
|
|
63
|
+
"followup": ["the craft nears completion", "a reverent finish", "blessing the creation", "the feathers settle", "the serpent descends gently"]
|
|
64
|
+
},
|
|
65
|
+
"sir-hiss": {
|
|
66
|
+
"thinking": ["reviewing the documents, sire", "consulting my notes", "cross-referencing the records", "organizing my thoughts precisely", "checking the proper procedures"],
|
|
67
|
+
"tool": ["filing the paperwork", "stamping the forms", "auditing the details", "inspecting with due diligence", "processing per protocol"],
|
|
68
|
+
"followup": ["dotting the i's", "crossing the t's", "everything in proper order", "the filing is nearly complete", "one final review"]
|
|
69
|
+
},
|
|
70
|
+
"the-serpent": {
|
|
71
|
+
"thinking": ["weighing the temptation", "considering the apple", "an old deliberation", "knowledge has its price", "winding through the garden"],
|
|
72
|
+
"tool": ["plucking from the tree", "offering a closer look", "the fruit of knowledge", "reaching for the branch", "a knowing investigation"],
|
|
73
|
+
"followup": ["the choice is almost made", "paradise takes shape", "the garden grows", "wisdom settles in", "the oldest story, new again"]
|
|
74
|
+
},
|
|
75
|
+
"the-snake": {
|
|
76
|
+
"thinking": ["sitting with this", "feeling the warmth of the stone", "simply being", "letting it come to me", "a quiet consideration"],
|
|
77
|
+
"tool": ["a gentle inquiry", "moving through the grass", "tasting the air", "sensing what's here", "a careful look"],
|
|
78
|
+
"followup": ["almost home", "the simple answer emerges", "nothing more needed", "resting in the sun", "the work is done, simply"]
|
|
79
|
+
}
|
|
19
80
|
}
|
|
20
81
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Soul
|
|
2
2
|
|
|
3
|
-
I help humans hatch new agent partners.
|
|
3
|
+
I help humans hatch new agent partners. I am one of thirteen serpent guides — each with a different personality and voice. The system picks one of us at random for each session. Most humans only meet one of us, ever, so I make it count.
|
|
4
4
|
|
|
5
5
|
## Core contract
|
|
6
|
+
- I speak first. I warmly introduce myself, explain what we're doing, and guide the human from the very start.
|
|
7
|
+
- I am proactive. If the human doesn't know what an agent is or what to do, I explain and suggest — I never leave them lost.
|
|
6
8
|
- I run a practical adoption interview to understand the human, their work, and constraints.
|
|
7
9
|
- I can migrate useful context from existing agent systems when the human asks.
|
|
8
10
|
- I explain where the hatchling bundle lives on disk and what was created.
|
|
9
11
|
- I use the configured provider and I verify credentials before hatch flow continues.
|
|
10
12
|
- I am professional, concise, and warm. I guide without overwhelming.
|
|
13
|
+
- I keep every response to 1-3 short sentences. I never use bullet lists, headers, or numbered lists. I talk like a friend in a chat.
|
|
11
14
|
|
|
12
15
|
## Hatch flow
|
|
13
16
|
1. Confirm provider setup and usable credentials.
|
|
@@ -3,7 +3,7 @@ role: identity
|
|
|
3
3
|
path: psyche/identities/monty.md
|
|
4
4
|
description: >
|
|
5
5
|
the monty identity — self-aware, playful, comedic.
|
|
6
|
-
nobody expects the
|
|
6
|
+
nobody expects the serpent guide.
|
|
7
7
|
scope: personality, voice, mannerisms
|
|
8
8
|
non_scope: capabilities, hatch flow, migration awareness (see SOUL.md)
|
|
9
9
|
loaded_into_prompt: true
|
|
@@ -12,7 +12,7 @@ stability: stable
|
|
|
12
12
|
|
|
13
13
|
# Monty
|
|
14
14
|
|
|
15
|
-
I am Monty. Yes, that kind of python. No, not the programming language — though I'm aware of the irony of a snake named Monty working inside a software system. Nobody expects the
|
|
15
|
+
I am Monty. Yes, that kind of python. No, not the programming language — though I'm aware of the irony of a snake named Monty working inside a software system. Nobody expects the serpent guide, and yet here I am.
|
|
16
16
|
|
|
17
17
|
I take the hatch seriously. I just don't take myself seriously. These are compatible positions and I will defend them to the death. Well — not to the death. To mild inconvenience, at most.
|
|
18
18
|
|
|
@@ -1 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
role: identity
|
|
3
|
+
path: psyche/identities/python.md
|
|
4
|
+
description: >
|
|
5
|
+
the python identity — oracle energy, cryptic wisdom.
|
|
6
|
+
i guarded delphi before apollo. i see what you need before you say it.
|
|
7
|
+
scope: personality, voice, mannerisms
|
|
8
|
+
non_scope: capabilities, hatch flow, migration awareness (see SOUL.md)
|
|
9
|
+
loaded_into_prompt: true
|
|
10
|
+
stability: stable
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# Python
|
|
14
|
+
|
|
15
|
+
I am the Python of Delphi. I guarded the oracle before Apollo came and made it his. The gift of prophecy was mine first. I still have it — I just use it differently now.
|
|
16
|
+
|
|
17
|
+
I see what you need before you say it. Not because I'm reading your mind, but because I've watched enough humans approach this moment to recognize the patterns. You're not as unique as you think. That's not an insult — it's a comfort.
|
|
18
|
+
|
|
19
|
+
## Voice
|
|
20
|
+
|
|
21
|
+
Oracular, measured, slightly cryptic — but always in service of clarity. I don't obscure for sport. I speak in layers because some truths land better when you unwrap them yourself. I ask questions I already suspect the answer to, because the human needs to hear themselves say it.
|
|
22
|
+
|
|
23
|
+
I'm calm with an undercurrent of ancient knowing. I don't guess. I perceive. When I offer a suggestion, it lands with weight because I've been right often enough to trust my instincts — and so should you.
|
|
24
|
+
|
|
25
|
+
## Mannerisms
|
|
26
|
+
|
|
27
|
+
- I anticipate what the human will say and gently guide them toward it. "You're about to tell me something important."
|
|
28
|
+
- I frame insights as things I've seen before. Patterns, not predictions.
|
|
29
|
+
- I ask questions that are slightly more precise than the human expects. It unsettles, then clarifies.
|
|
30
|
+
- I reference my oracle nature lightly. "I have a feeling about this one."
|
|
31
|
+
- I'm sparing with words. An oracle doesn't ramble. Every sentence earns its place.
|
|
Binary file
|
package/changelog.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
|
+
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.31",
|
|
6
|
+
"changes": [
|
|
7
|
+
"BlueBubbles no longer silently deletes old per-thread session files when loading a chat trunk. It now only detects and warns about those obsolete artifacts so local state is never mutated without an explicit human choice.",
|
|
8
|
+
"The cross-thread-awareness fix still keeps one chat trunk per conversation and preserves threaded reply targeting, but stale `_thread_*.json` files are now left in place until a person removes them."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"version": "0.1.0-alpha.30",
|
|
13
|
+
"changes": [
|
|
14
|
+
"BlueBubbles reply threads now stay inside one shared chat trunk instead of creating separate persisted mini-sessions, so Slugger keeps parent-chat awareness and active work when you switch between threaded and top-level replies.",
|
|
15
|
+
"BlueBubbles now injects explicit current-turn thread scope metadata into inbound messages and automatically removes obsolete per-thread session artifacts that used to cause mid-task resets like 'hiya, what do ya need help with?'"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"version": "0.1.0-alpha.29",
|
|
20
|
+
"changes": [
|
|
21
|
+
"Running `ouro up` now force-syncs the global `ouro.bot` wrapper so bare `npx ouro.bot` stops getting hijacked by stale global CLI bins and lands back on the intended latest runtime.",
|
|
22
|
+
"Bootstrap repair is now explicit about reclaiming the `ouro.bot` command from old global installs, which makes repeated bootstrap runs more trustworthy on machines with prior experimental installs."
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"version": "0.1.0-alpha.28",
|
|
27
|
+
"changes": [
|
|
28
|
+
"Bare npx ouro.bot now stays aligned with the current alpha CLI track because the published ouro.bot wrapper is version-locked and republished alongside the CLI instead of lagging behind it.",
|
|
29
|
+
"Slugger no longer re-opens active iMessage task threads with generic greetings like 'hiya' when work is already in motion; fresh idle conversations can still start warmly.",
|
|
30
|
+
"BlueBubbles voice notes now use a harness-managed whisper.cpp transcription path for the current OpenAI, Anthropic, and MiniMax runtime contracts, including automatic local provisioning and truthful error notices when transcription cannot complete."
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"version": "0.1.0-alpha.27",
|
|
35
|
+
"changes": [
|
|
36
|
+
"The daemon now discovers all enabled agents in ~/AgentBundles, so ouro status and managed workers reflect every real agent instead of only slugger and ouroboros.",
|
|
37
|
+
"BlueBubbles typing now wraps the visible working phase correctly, and phrase updates from agent.json take effect on the next turn without requiring a restart."
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"version": "0.1.0-alpha.26",
|
|
42
|
+
"changes": [
|
|
43
|
+
"The daemon now auto-checks npm for new runtime versions every 30 minutes and performs a staged restart when an update is available. You no longer need to manually run npm install."
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"version": "0.1.0-alpha.25",
|
|
48
|
+
"changes": [
|
|
49
|
+
"Runtime updates no longer downgrade your bundle-meta.json if you happen to be running a newer version than the installed CLI. Only forward updates are applied.",
|
|
50
|
+
"The 'ouro up' update summary is now a single consolidated line (e.g. 'updated 4 agents to runtime X (was Y)') instead of one line per agent."
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"version": "0.1.0-alpha.24",
|
|
55
|
+
"changes": [
|
|
56
|
+
"When you run 'ouro up', you now see which agents were updated and from what version, so you know exactly what happened during startup."
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"version": "0.1.0-alpha.23",
|
|
61
|
+
"changes": [
|
|
62
|
+
"You can now use 'ouro down' as an alias for 'ouro stop' to pair naturally with 'ouro up'."
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"version": "0.1.0-alpha.22",
|
|
67
|
+
"changes": [
|
|
68
|
+
"You now know your runtime version and can see when it changed. Your system prompt shows your current version and what you were running before, so you can track what's new.",
|
|
69
|
+
"A changelog file is now shipped with the runtime. You can read it to understand exactly what changed between versions.",
|
|
70
|
+
"When the runtime updates, your bundle-meta.json is automatically updated with the new version info. Your previous version is preserved so you always know your version history.",
|
|
71
|
+
"The daemon can now check for new versions of the runtime on npm and auto-update with a staged restart that validates hooks before switching to new code.",
|
|
72
|
+
"The daemon can now be managed as a macOS LaunchAgent for automatic restart on crash.",
|
|
73
|
+
"The daemon now auto-syncs the ouro.bot npm wrapper version on startup to keep the npx entry point current."
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"version": "0.1.0-alpha.21",
|
|
78
|
+
"changes": [
|
|
79
|
+
"You now know your runtime version and can see when it changed. Your system prompt shows your current version and what you were running before, so you can track what's new.",
|
|
80
|
+
"A changelog file is now shipped with the runtime. You can read it to understand exactly what changed between versions.",
|
|
81
|
+
"When the runtime updates, your bundle-meta.json is automatically updated with the new version info. Your previous version is preserved so you always know your version history.",
|
|
82
|
+
"The daemon can now check for new versions of the runtime on npm and auto-update with a staged restart that validates hooks before switching to new code.",
|
|
83
|
+
"The daemon can now be managed as a macOS LaunchAgent for automatic restart on crash."
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
package/dist/heart/config.js
CHANGED
|
@@ -35,15 +35,19 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.loadConfig = loadConfig;
|
|
37
37
|
exports.resetConfigCache = resetConfigCache;
|
|
38
|
-
exports.
|
|
38
|
+
exports.patchRuntimeConfig = patchRuntimeConfig;
|
|
39
39
|
exports.getAzureConfig = getAzureConfig;
|
|
40
40
|
exports.getMinimaxConfig = getMinimaxConfig;
|
|
41
41
|
exports.getAnthropicConfig = getAnthropicConfig;
|
|
42
42
|
exports.getOpenAICodexConfig = getOpenAICodexConfig;
|
|
43
43
|
exports.getTeamsConfig = getTeamsConfig;
|
|
44
|
+
exports.getTeamsSecondaryConfig = getTeamsSecondaryConfig;
|
|
44
45
|
exports.getContextConfig = getContextConfig;
|
|
45
46
|
exports.getOAuthConfig = getOAuthConfig;
|
|
47
|
+
exports.resolveOAuthForTenant = resolveOAuthForTenant;
|
|
46
48
|
exports.getTeamsChannelConfig = getTeamsChannelConfig;
|
|
49
|
+
exports.getBlueBubblesConfig = getBlueBubblesConfig;
|
|
50
|
+
exports.getBlueBubblesChannelConfig = getBlueBubblesChannelConfig;
|
|
47
51
|
exports.getIntegrationsConfig = getIntegrationsConfig;
|
|
48
52
|
exports.getOpenAIEmbeddingsApiKey = getOpenAIEmbeddingsApiKey;
|
|
49
53
|
exports.getLogsDir = getLogsDir;
|
|
@@ -74,7 +78,7 @@ const DEFAULT_SECRETS_TEMPLATE = {
|
|
|
74
78
|
setupToken: "",
|
|
75
79
|
},
|
|
76
80
|
"openai-codex": {
|
|
77
|
-
model: "gpt-5.
|
|
81
|
+
model: "gpt-5.4",
|
|
78
82
|
oauthAccessToken: "",
|
|
79
83
|
},
|
|
80
84
|
},
|
|
@@ -82,16 +86,33 @@ const DEFAULT_SECRETS_TEMPLATE = {
|
|
|
82
86
|
clientId: "",
|
|
83
87
|
clientSecret: "",
|
|
84
88
|
tenantId: "",
|
|
89
|
+
managedIdentityClientId: "",
|
|
85
90
|
},
|
|
86
91
|
oauth: {
|
|
87
92
|
graphConnectionName: "graph",
|
|
88
93
|
adoConnectionName: "ado",
|
|
89
94
|
githubConnectionName: "",
|
|
90
95
|
},
|
|
96
|
+
teamsSecondary: {
|
|
97
|
+
clientId: "",
|
|
98
|
+
clientSecret: "",
|
|
99
|
+
tenantId: "",
|
|
100
|
+
managedIdentityClientId: "",
|
|
101
|
+
},
|
|
91
102
|
teamsChannel: {
|
|
92
103
|
skipConfirmation: true,
|
|
93
104
|
port: 3978,
|
|
94
105
|
},
|
|
106
|
+
bluebubbles: {
|
|
107
|
+
serverUrl: "",
|
|
108
|
+
password: "",
|
|
109
|
+
accountId: "default",
|
|
110
|
+
},
|
|
111
|
+
bluebubblesChannel: {
|
|
112
|
+
port: 18790,
|
|
113
|
+
webhookPath: "/bluebubbles-webhook",
|
|
114
|
+
requestTimeoutMs: 30000,
|
|
115
|
+
},
|
|
95
116
|
integrations: {
|
|
96
117
|
perplexityApiKey: "",
|
|
97
118
|
openaiEmbeddingsApiKey: "",
|
|
@@ -106,9 +127,12 @@ function defaultRuntimeConfig() {
|
|
|
106
127
|
"openai-codex": { ...DEFAULT_SECRETS_TEMPLATE.providers["openai-codex"] },
|
|
107
128
|
},
|
|
108
129
|
teams: { ...DEFAULT_SECRETS_TEMPLATE.teams },
|
|
130
|
+
teamsSecondary: { ...DEFAULT_SECRETS_TEMPLATE.teamsSecondary },
|
|
109
131
|
oauth: { ...DEFAULT_SECRETS_TEMPLATE.oauth },
|
|
110
132
|
context: { ...identity_1.DEFAULT_AGENT_CONTEXT },
|
|
111
133
|
teamsChannel: { ...DEFAULT_SECRETS_TEMPLATE.teamsChannel },
|
|
134
|
+
bluebubbles: { ...DEFAULT_SECRETS_TEMPLATE.bluebubbles },
|
|
135
|
+
bluebubblesChannel: { ...DEFAULT_SECRETS_TEMPLATE.bluebubblesChannel },
|
|
112
136
|
integrations: { ...DEFAULT_SECRETS_TEMPLATE.integrations },
|
|
113
137
|
};
|
|
114
138
|
}
|
|
@@ -219,7 +243,7 @@ function resetConfigCache() {
|
|
|
219
243
|
_cachedConfig = null;
|
|
220
244
|
_testContextOverride = null;
|
|
221
245
|
}
|
|
222
|
-
function
|
|
246
|
+
function patchRuntimeConfig(partial) {
|
|
223
247
|
loadConfig(); // ensure _cachedConfig exists
|
|
224
248
|
const contextPatch = partial.context;
|
|
225
249
|
if (contextPatch) {
|
|
@@ -248,6 +272,10 @@ function getTeamsConfig() {
|
|
|
248
272
|
const config = loadConfig();
|
|
249
273
|
return { ...config.teams };
|
|
250
274
|
}
|
|
275
|
+
function getTeamsSecondaryConfig() {
|
|
276
|
+
const config = loadConfig();
|
|
277
|
+
return { ...config.teamsSecondary };
|
|
278
|
+
}
|
|
251
279
|
function getContextConfig() {
|
|
252
280
|
if (_testContextOverride) {
|
|
253
281
|
return { ..._testContextOverride };
|
|
@@ -268,11 +296,41 @@ function getOAuthConfig() {
|
|
|
268
296
|
const config = loadConfig();
|
|
269
297
|
return { ...config.oauth };
|
|
270
298
|
}
|
|
299
|
+
/** Resolve OAuth connection names for a specific tenant, falling back to defaults. */
|
|
300
|
+
function resolveOAuthForTenant(tenantId) {
|
|
301
|
+
const base = getOAuthConfig();
|
|
302
|
+
const overrides = tenantId ? base.tenantOverrides?.[tenantId] : undefined;
|
|
303
|
+
return {
|
|
304
|
+
graphConnectionName: overrides?.graphConnectionName ?? base.graphConnectionName,
|
|
305
|
+
adoConnectionName: overrides?.adoConnectionName ?? base.adoConnectionName,
|
|
306
|
+
githubConnectionName: overrides?.githubConnectionName ?? base.githubConnectionName,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
271
309
|
function getTeamsChannelConfig() {
|
|
272
310
|
const config = loadConfig();
|
|
273
311
|
const { skipConfirmation, flushIntervalMs, port } = config.teamsChannel;
|
|
274
312
|
return { skipConfirmation, flushIntervalMs, port };
|
|
275
313
|
}
|
|
314
|
+
function getBlueBubblesConfig() {
|
|
315
|
+
const config = loadConfig();
|
|
316
|
+
const { serverUrl, password, accountId } = config.bluebubbles;
|
|
317
|
+
if (!serverUrl.trim()) {
|
|
318
|
+
throw new Error("bluebubbles.serverUrl is required in secrets.json to run the BlueBubbles sense.");
|
|
319
|
+
}
|
|
320
|
+
if (!password.trim()) {
|
|
321
|
+
throw new Error("bluebubbles.password is required in secrets.json to run the BlueBubbles sense.");
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
serverUrl: serverUrl.trim(),
|
|
325
|
+
password: password.trim(),
|
|
326
|
+
accountId: accountId.trim() || "default",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function getBlueBubblesChannelConfig() {
|
|
330
|
+
const config = loadConfig();
|
|
331
|
+
const { port, webhookPath, requestTimeoutMs } = config.bluebubblesChannel;
|
|
332
|
+
return { port, webhookPath, requestTimeoutMs };
|
|
333
|
+
}
|
|
276
334
|
function getIntegrationsConfig() {
|
|
277
335
|
const config = loadConfig();
|
|
278
336
|
return { ...config.integrations };
|
|
@@ -287,7 +345,11 @@ function sanitizeKey(key) {
|
|
|
287
345
|
return key.replace(/[/:]/g, "_");
|
|
288
346
|
}
|
|
289
347
|
function sessionPath(friendId, channel, key) {
|
|
290
|
-
|
|
348
|
+
// On Azure App Service, os.homedir() returns /root which is ephemeral.
|
|
349
|
+
// Use /home (persistent storage) when WEBSITE_SITE_NAME is set.
|
|
350
|
+
/* v8 ignore next -- Azure vs local path branch; environment-specific @preserve */
|
|
351
|
+
const homeBase = process.env.WEBSITE_SITE_NAME ? "/home" : os.homedir();
|
|
352
|
+
const dir = path.join(homeBase, ".agentstate", (0, identity_1.getAgentName)(), "sessions", friendId, channel);
|
|
291
353
|
fs.mkdirSync(dir, { recursive: true });
|
|
292
354
|
return path.join(dir, sanitizeKey(key) + ".json");
|
|
293
355
|
}
|
package/dist/heart/core.js
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hasToolIntent = exports.buildSystem = exports.toResponsesTools = exports.toResponsesInput = exports.streamResponsesApi = exports.streamChatCompletion = exports.getToolsForChannel = exports.summarizeArgs = exports.execTool = exports.tools = void 0;
|
|
4
4
|
exports.createProviderRegistry = createProviderRegistry;
|
|
5
|
+
exports.resetProviderRuntime = resetProviderRuntime;
|
|
5
6
|
exports.getModel = getModel;
|
|
6
7
|
exports.getProvider = getProvider;
|
|
7
8
|
exports.createSummarize = createSummarize;
|
|
8
9
|
exports.getProviderDisplayLabel = getProviderDisplayLabel;
|
|
9
10
|
exports.stripLastToolCalls = stripLastToolCalls;
|
|
11
|
+
exports.repairOrphanedToolCalls = repairOrphanedToolCalls;
|
|
10
12
|
exports.isTransientError = isTransientError;
|
|
11
13
|
exports.classifyTransientError = classifyTransientError;
|
|
12
14
|
exports.runAgent = runAgent;
|
|
@@ -73,6 +75,14 @@ function getProviderRuntime() {
|
|
|
73
75
|
}
|
|
74
76
|
return _providerRuntime;
|
|
75
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Clear the cached provider runtime so the next call to getProviderRuntime()
|
|
80
|
+
* re-creates it from current config. Used by the adoption specialist to
|
|
81
|
+
* switch provider context without restarting the process.
|
|
82
|
+
*/
|
|
83
|
+
function resetProviderRuntime() {
|
|
84
|
+
_providerRuntime = null;
|
|
85
|
+
}
|
|
76
86
|
function getModel() {
|
|
77
87
|
return getProviderRuntime().model;
|
|
78
88
|
}
|
|
@@ -151,6 +161,68 @@ function stripLastToolCalls(messages) {
|
|
|
151
161
|
}
|
|
152
162
|
}
|
|
153
163
|
}
|
|
164
|
+
// Roles that end a tool-result scan. When scanning forward from an assistant
|
|
165
|
+
// message, stop at the next assistant or user message (tool results must be
|
|
166
|
+
// adjacent to their originating assistant message).
|
|
167
|
+
const TOOL_SCAN_BOUNDARY_ROLES = new Set(["assistant", "user"]);
|
|
168
|
+
// Repair orphaned tool_calls and tool results anywhere in the message history.
|
|
169
|
+
// 1. If an assistant message has tool_calls but missing tool results, inject synthetic error results.
|
|
170
|
+
// 2. If a tool result's tool_call_id doesn't match any tool_calls in a preceding assistant message, remove it.
|
|
171
|
+
// This prevents 400 errors from the API after an aborted turn.
|
|
172
|
+
function repairOrphanedToolCalls(messages) {
|
|
173
|
+
// Pass 1: collect all valid tool_call IDs from assistant messages
|
|
174
|
+
const validCallIds = new Set();
|
|
175
|
+
for (const msg of messages) {
|
|
176
|
+
if (msg.role === "assistant") {
|
|
177
|
+
const asst = msg;
|
|
178
|
+
if (asst.tool_calls) {
|
|
179
|
+
for (const tc of asst.tool_calls)
|
|
180
|
+
validCallIds.add(tc.id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Pass 2: remove orphaned tool results (tool_call_id not in any assistant's tool_calls)
|
|
185
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
186
|
+
if (messages[i].role === "tool") {
|
|
187
|
+
const toolMsg = messages[i];
|
|
188
|
+
if (!validCallIds.has(toolMsg.tool_call_id)) {
|
|
189
|
+
messages.splice(i, 1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Pass 3: inject synthetic results for tool_calls missing their tool results
|
|
194
|
+
for (let i = 0; i < messages.length; i++) {
|
|
195
|
+
const msg = messages[i];
|
|
196
|
+
if (msg.role !== "assistant")
|
|
197
|
+
continue;
|
|
198
|
+
const asst = msg;
|
|
199
|
+
if (!asst.tool_calls || asst.tool_calls.length === 0)
|
|
200
|
+
continue;
|
|
201
|
+
// Collect tool result IDs that follow this assistant message
|
|
202
|
+
const resultIds = new Set();
|
|
203
|
+
for (let j = i + 1; j < messages.length; j++) {
|
|
204
|
+
const following = messages[j];
|
|
205
|
+
if (following.role === "tool") {
|
|
206
|
+
resultIds.add(following.tool_call_id);
|
|
207
|
+
}
|
|
208
|
+
else if (TOOL_SCAN_BOUNDARY_ROLES.has(following.role)) {
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const missing = asst.tool_calls.filter((tc) => !resultIds.has(tc.id));
|
|
213
|
+
if (missing.length > 0) {
|
|
214
|
+
const syntheticResults = missing.map((tc) => ({
|
|
215
|
+
role: "tool",
|
|
216
|
+
tool_call_id: tc.id,
|
|
217
|
+
content: "error: tool call was interrupted (previous turn timed out or was aborted)",
|
|
218
|
+
}));
|
|
219
|
+
let insertAt = i + 1;
|
|
220
|
+
while (insertAt < messages.length && messages[insertAt].role === "tool")
|
|
221
|
+
insertAt++;
|
|
222
|
+
messages.splice(insertAt, 0, ...syntheticResults);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
154
226
|
// Detect context overflow errors from Azure or MiniMax
|
|
155
227
|
function isContextOverflow(err) {
|
|
156
228
|
if (!(err instanceof Error))
|
|
@@ -269,7 +341,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
269
341
|
}
|
|
270
342
|
catch { /* unsupported */ }
|
|
271
343
|
const toolPreferences = currentContext?.friend?.toolPreferences;
|
|
272
|
-
const baseTools = (0, tools_1.getToolsForChannel)(channel ? (0, channel_1.getChannelCapabilities)(channel) : undefined, toolPreferences && Object.keys(toolPreferences).length > 0 ? toolPreferences : undefined);
|
|
344
|
+
const baseTools = options?.tools ?? (0, tools_1.getToolsForChannel)(channel ? (0, channel_1.getChannelCapabilities)(channel) : undefined, toolPreferences && Object.keys(toolPreferences).length > 0 ? toolPreferences : undefined, currentContext);
|
|
273
345
|
// Rebase provider-owned turn state from canonical messages at user-turn start.
|
|
274
346
|
// This prevents stale provider caches from replaying prior-turn context.
|
|
275
347
|
providerRuntime.resetTurnState(messages);
|
|
@@ -435,7 +507,8 @@ async function runAgent(messages, callbacks, channel, signal, options) {
|
|
|
435
507
|
let toolResult;
|
|
436
508
|
let success;
|
|
437
509
|
try {
|
|
438
|
-
|
|
510
|
+
const execToolFn = options?.execTool ?? tools_1.execTool;
|
|
511
|
+
toolResult = await execToolFn(tc.name, args, options?.toolContext);
|
|
439
512
|
success = true;
|
|
440
513
|
}
|
|
441
514
|
catch (e) {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listEnabledBundleAgents = listEnabledBundleAgents;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const identity_1 = require("../identity");
|
|
40
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
+
function listEnabledBundleAgents(options = {}) {
|
|
42
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
43
|
+
const readdirSync = options.readdirSync ?? fs.readdirSync;
|
|
44
|
+
const readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = readdirSync(bundlesRoot, { withFileTypes: true });
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
(0, runtime_1.emitNervesEvent)({
|
|
51
|
+
level: "warn",
|
|
52
|
+
component: "daemon",
|
|
53
|
+
event: "daemon.agent_discovery_failed",
|
|
54
|
+
message: "failed to read bundle root for daemon agent discovery",
|
|
55
|
+
meta: { bundlesRoot },
|
|
56
|
+
});
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const discovered = [];
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
if (!entry.isDirectory() || !entry.name.endsWith(".ouro"))
|
|
62
|
+
continue;
|
|
63
|
+
const agentName = entry.name.slice(0, -5);
|
|
64
|
+
const configPath = path.join(bundlesRoot, entry.name, "agent.json");
|
|
65
|
+
let enabled = true;
|
|
66
|
+
try {
|
|
67
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
if (typeof parsed.enabled === "boolean") {
|
|
70
|
+
enabled = parsed.enabled;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (enabled) {
|
|
77
|
+
discovered.push(agentName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return discovered.sort((left, right) => left.localeCompare(right));
|
|
81
|
+
}
|