@geravant/sinain 1.18.1 → 1.18.2
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,54 @@ 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
183
|
escalationMode: "off",
|
|
165
|
-
// Don't touch openclawProfile in quickstart — keeps existing config
|
|
166
|
-
// intact for re-runs; first-time users get the "skip" state from
|
|
167
|
-
// agents.example.json bootstrap (no openclaw profile means no gateway).
|
|
168
184
|
};
|
|
169
185
|
|
|
186
|
+
if (enableGateway) {
|
|
187
|
+
// Walk through full gateway setup (URL, tokens, session key) — same
|
|
188
|
+
// step Advanced uses. Returns { envVars, agentsPatch } we merge in.
|
|
189
|
+
const gatewayResult = await stepGateway(base, "OpenClaw gateway");
|
|
190
|
+
Object.assign(vars, gatewayResult.envVars);
|
|
191
|
+
Object.assign(agentsPatch, gatewayResult.agentsPatch);
|
|
192
|
+
} else {
|
|
193
|
+
// Explicitly clear any inherited openclaw profile so the runtime
|
|
194
|
+
// doesn't auto-register the gateway or attempt WS reconnects.
|
|
195
|
+
agentsPatch.openclawProfile = null;
|
|
196
|
+
}
|
|
197
|
+
|
|
170
198
|
p.note(
|
|
171
199
|
[
|
|
172
200
|
`Transcription: ${vars.TRANSCRIPTION_BACKEND}`,
|
|
173
201
|
`Privacy: ${vars.PRIVACY_MODE}`,
|
|
174
202
|
`Model: ${vars.AGENT_MODEL}`,
|
|
175
|
-
`
|
|
203
|
+
`OpenClaw gateway: ${enableGateway ? "enabled" : "disabled"}`,
|
|
204
|
+
`Escalation: ${agentsPatch.escalationMode || "off"}`,
|
|
176
205
|
"",
|
|
177
206
|
`Change later: sinain config`,
|
|
178
207
|
].join("\n"),
|
|
@@ -368,10 +397,9 @@ if (flags.nonInteractive) {
|
|
|
368
397
|
}
|
|
369
398
|
|
|
370
399
|
writeEnv(vars);
|
|
371
|
-
// Default agent + escalation off
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
writeAgentsConfig({ default: "claude", escalationMode: "off" });
|
|
400
|
+
// Default agent + escalation off + openclaw explicitly disabled. Gateway is
|
|
401
|
+
// opt-in via the interactive wizard (`sinain onboard`) or `sinain config`.
|
|
402
|
+
writeAgentsConfig({ default: "claude", escalationMode: "off", openclawProfile: null });
|
|
375
403
|
console.log(c.green(` Config written to ${ENV_PATH} + ~/.sinain/agents.json`));
|
|
376
404
|
process.exit(0);
|
|
377
405
|
} else {
|
package/package.json
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
"escalation": {
|
|
67
|
-
"mode": "
|
|
67
|
+
"mode": "off",
|
|
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 = {
|