@geravant/sinain 1.18.1 → 1.18.3
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/onboard.js
CHANGED
|
@@ -154,25 +154,58 @@ export async function runOnboard(args = {}) {
|
|
|
154
154
|
p.log.success("API key saved.");
|
|
155
155
|
|
|
156
156
|
if (flow === "quickstart") {
|
|
157
|
-
// QuickStart: sensible defaults
|
|
158
|
-
//
|
|
157
|
+
// QuickStart: sensible defaults + a single opt-in question for OpenClaw.
|
|
158
|
+
// Gateway integration is off by default; users who want it run Advanced
|
|
159
|
+
// (or answer Yes here, which then walks them through stepGateway).
|
|
159
160
|
vars.TRANSCRIPTION_BACKEND = base.TRANSCRIPTION_BACKEND || "openrouter";
|
|
160
161
|
vars.PRIVACY_MODE = base.PRIVACY_MODE || "standard";
|
|
161
162
|
vars.AGENT_MODEL = base.AGENT_MODEL || "google/gemini-2.5-flash-lite";
|
|
163
|
+
|
|
164
|
+
// Ask explicitly so first-run installs don't silently inherit a gateway
|
|
165
|
+
// profile from agents.example.json. Default reflects current state — No
|
|
166
|
+
// for fresh installs (silences the WS reconnect loop), Yes for re-runs
|
|
167
|
+
// that already had OpenClaw configured (so we don't surprise-delete it).
|
|
168
|
+
const hasExistingGateway = (() => {
|
|
169
|
+
try {
|
|
170
|
+
const agentsPath = path.join(SINAIN_DIR, "agents.json");
|
|
171
|
+
if (!fs.existsSync(agentsPath)) return false;
|
|
172
|
+
const cfg = JSON.parse(fs.readFileSync(agentsPath, "utf-8"));
|
|
173
|
+
return !!cfg?.profiles?.openclaw;
|
|
174
|
+
} catch { return false; }
|
|
175
|
+
})();
|
|
176
|
+
const enableGateway = guard(await p.confirm({
|
|
177
|
+
message: "Enable OpenClaw gateway integration?",
|
|
178
|
+
initialValue: hasExistingGateway,
|
|
179
|
+
}));
|
|
180
|
+
|
|
162
181
|
agentsPatch = {
|
|
163
182
|
default: base.SINAIN_AGENT || "claude",
|
|
164
|
-
escalationMode
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
183
|
+
// No `escalationMode` written — lane (default agent) is the single
|
|
184
|
+
// source of truth for whether escalation runs. If the user picks a
|
|
185
|
+
// local agent (claude), the runtime's default mode ("rich" from
|
|
186
|
+
// config.ts) takes effect and registerBareAgent ensures lane and
|
|
187
|
+
// mode stay reconciled at boot.
|
|
168
188
|
};
|
|
169
189
|
|
|
190
|
+
if (enableGateway) {
|
|
191
|
+
// Walk through full gateway setup (URL, tokens, session key) — same
|
|
192
|
+
// step Advanced uses. Returns { envVars, agentsPatch } we merge in.
|
|
193
|
+
const gatewayResult = await stepGateway(base, "OpenClaw gateway");
|
|
194
|
+
Object.assign(vars, gatewayResult.envVars);
|
|
195
|
+
Object.assign(agentsPatch, gatewayResult.agentsPatch);
|
|
196
|
+
} else {
|
|
197
|
+
// Explicitly clear any inherited openclaw profile so the runtime
|
|
198
|
+
// doesn't auto-register the gateway or attempt WS reconnects.
|
|
199
|
+
agentsPatch.openclawProfile = null;
|
|
200
|
+
}
|
|
201
|
+
|
|
170
202
|
p.note(
|
|
171
203
|
[
|
|
172
204
|
`Transcription: ${vars.TRANSCRIPTION_BACKEND}`,
|
|
173
205
|
`Privacy: ${vars.PRIVACY_MODE}`,
|
|
174
206
|
`Model: ${vars.AGENT_MODEL}`,
|
|
175
|
-
`
|
|
207
|
+
`OpenClaw gateway: ${enableGateway ? "enabled" : "disabled"}`,
|
|
208
|
+
`Escalation: ${agentsPatch.escalationMode || "off"}`,
|
|
176
209
|
"",
|
|
177
210
|
`Change later: sinain config`,
|
|
178
211
|
].join("\n"),
|
|
@@ -368,10 +401,9 @@ if (flags.nonInteractive) {
|
|
|
368
401
|
}
|
|
369
402
|
|
|
370
403
|
writeEnv(vars);
|
|
371
|
-
// Default agent +
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
writeAgentsConfig({ default: "claude", escalationMode: "off" });
|
|
404
|
+
// Default agent + openclaw explicitly disabled. No escalation mode written
|
|
405
|
+
// — lane is the source of truth, registerBareAgent reconciles at boot.
|
|
406
|
+
writeAgentsConfig({ default: "claude", openclawProfile: null });
|
|
375
407
|
console.log(c.green(` Config written to ${ENV_PATH} + ~/.sinain/agents.json`));
|
|
376
408
|
process.exit(0);
|
|
377
409
|
} else {
|
package/package.json
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
"escalation": {
|
|
67
|
-
"
|
|
67
|
+
"_comment": "Lane (the agent picked for escalation in agents.json `default` or via the overlay chip) is the source of truth for whether escalation runs. `mode` is intentionally omitted here — the runtime default (rich) applies, and registerBareAgent reconciles mode with lane at boot. Override `mode` only if you want to force selective/focus/off semantics.",
|
|
68
68
|
"cooldownMs": 30000,
|
|
69
69
|
"staleMs": 90000
|
|
70
70
|
},
|
|
@@ -81,8 +81,15 @@
|
|
|
81
81
|
"OPENAI_API_KEY": "${OPENROUTER_API_KEY}"
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
|
+
"codex": { "type": "codex" },
|
|
85
|
+
"goose": { "type": "goose" },
|
|
86
|
+
"junie": { "type": "junie" },
|
|
87
|
+
"aider": { "type": "aider" }
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
"_examples": {
|
|
84
91
|
"openclaw": {
|
|
85
|
-
"_comment": "
|
|
92
|
+
"_comment": "OpenClaw gateway routing. Move this entry into `profiles` to enable. The wizard's `sinain onboard --advanced` step or `sinain config gateway` populates this section automatically with your gateway URL/tokens. Selecting openclaw for a lane sends that lane's traffic via WS RPC to the gateway instead of the local bare agent. Disabled by default so first-run installs don't attempt WS connections to a gateway that isn't running.",
|
|
86
93
|
"type": "openclaw",
|
|
87
94
|
"wsUrl": "ws://localhost:18789",
|
|
88
95
|
"wsToken": "${OPENCLAW_WS_TOKEN}",
|
|
@@ -93,13 +100,6 @@
|
|
|
93
100
|
"phase2TimeoutMs": 120000,
|
|
94
101
|
"pingIntervalMs": 30000
|
|
95
102
|
},
|
|
96
|
-
"codex": { "type": "codex" },
|
|
97
|
-
"goose": { "type": "goose" },
|
|
98
|
-
"junie": { "type": "junie" },
|
|
99
|
-
"aider": { "type": "aider" }
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
"_examples": {
|
|
103
103
|
"pclaude": {
|
|
104
104
|
"_comment": "Personal claude config. `bin` must be a real PATH binary — replicate a shell alias as bin+env (the alias `pclaude=CLAUDE_CONFIG_DIR=$HOME/.claude-personal claude` becomes the entry below).",
|
|
105
105
|
"type": "claude",
|
|
@@ -99,6 +99,12 @@ export class Escalator {
|
|
|
99
99
|
// Store context from last escalation for response handling
|
|
100
100
|
private lastEscalationContext: ContextWindow | null = null;
|
|
101
101
|
|
|
102
|
+
// Knowledge enrichment is skipped on the very first escalation per process
|
|
103
|
+
// to avoid the 5s fetchKnowledgeFacts() cold-start tax on user-perceived
|
|
104
|
+
// first-response latency. Each subsequent escalation does its own fetch
|
|
105
|
+
// independently — no cross-escalation cache, no shared content state.
|
|
106
|
+
private firstEscalationDone = false;
|
|
107
|
+
|
|
102
108
|
// User command to inject into the next escalation
|
|
103
109
|
private pendingUserCommand: UserCommand | null = null;
|
|
104
110
|
private static readonly USER_COMMAND_EXPIRY_MS = 120_000; // 2 minutes
|
|
@@ -281,8 +287,10 @@ export class Escalator {
|
|
|
281
287
|
// Clear user command after building the message (consumed once)
|
|
282
288
|
this.pendingUserCommand = null;
|
|
283
289
|
|
|
284
|
-
// Enrich with long-term knowledge facts (best-effort, 5s max)
|
|
285
|
-
|
|
290
|
+
// Enrich with long-term knowledge facts (best-effort, 5s max).
|
|
291
|
+
// Skipped on the inaugural escalation per process to eliminate cold-start
|
|
292
|
+
// latency — the user's first response shouldn't wait for KG warmup.
|
|
293
|
+
if (this.deps.queryKnowledgeFacts && this.firstEscalationDone) {
|
|
286
294
|
try {
|
|
287
295
|
const knowledgeSection = await fetchKnowledgeFacts(
|
|
288
296
|
contextWindow, entry.digest, this.deps.queryKnowledgeFacts,
|
|
@@ -294,7 +302,10 @@ export class Escalator {
|
|
|
294
302
|
} catch (err) {
|
|
295
303
|
log(TAG, `knowledge enrichment failed: ${String(err)}`);
|
|
296
304
|
}
|
|
305
|
+
} else if (!this.firstEscalationDone) {
|
|
306
|
+
log(TAG, `first escalation: skipping knowledge fetch (fast path)`);
|
|
297
307
|
}
|
|
308
|
+
this.firstEscalationDone = true;
|
|
298
309
|
|
|
299
310
|
const slotId = createHash("sha256").update(this.deps.openclawConfig.sessionKey + entry.ts).digest("hex").slice(0, 16);
|
|
300
311
|
const slotEntry: SlotEntry = {
|
package/sinain-core/src/index.ts
CHANGED
|
@@ -734,6 +734,16 @@ async function main() {
|
|
|
734
734
|
}
|
|
735
735
|
wsHandler.updateState({ agents: { ...bareAgentState } });
|
|
736
736
|
log(TAG, `bareagent register: available=[${clean.join(",")}] current=${current} → lanes esc=${bareAgentState.escalationAgent} spawn=${bareAgentState.spawnAgent}`);
|
|
737
|
+
|
|
738
|
+
// Lane is the source of truth for "is escalation active?". If a lane is
|
|
739
|
+
// set but mode is still "off" (e.g. an old wizard run wrote mode=off and
|
|
740
|
+
// the user has since picked an agent in the chip selector — or we just
|
|
741
|
+
// booted from agents.json with that combination), reconcile by promoting
|
|
742
|
+
// mode to match. Mirrors the existing set_agent → resumeEscalation flow,
|
|
743
|
+
// applied at register time so the boot-from-disk case isn't an exception.
|
|
744
|
+
if (bareAgentState.escalationAgent && config.escalationConfig.mode === "off") {
|
|
745
|
+
resumeEscalationInternal();
|
|
746
|
+
}
|
|
737
747
|
}
|
|
738
748
|
|
|
739
749
|
// ── Create HTTP + WS server ──
|