MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / runTurn

Method runTurn

src/bot/runner.ts:80–173  ·  view source on GitHub ↗
(convKey: string, userText: string, sink: TurnSink, signal: AbortSignal)

Source from the content-addressed store, hash-verified

78 const { readEpisodes } = await import('../context/episodic-memory.js');
79 const sid = convKey ? await this.map.get(convKey) : undefined;
80 const eps = await readEpisodes(this.cwdFor(sid));
81 return eps.slice(-limit).reverse().map(e => ({ when: relTime(e.ts), prompt: e.prompt, summary: e.summary }));
82 }
83
84 /** Rebind a conversation to a past session by full id OR short prefix (as shown by /sessions). */
85 async resume(convKey: string, idOrPrefix: string): Promise<boolean> {
86 const store = getSessionStore();
87 const match = store.loadSession(idOrPrefix) ? idOrPrefix
88 : store.listRecentSessions(100).find(s => s.id.startsWith(idOrPrefix))?.id;
89 if (!match) return false;
90 await this.map.set(convKey, match);
91 return true;
92 }
93
94 async runTurn(convKey: string, userText: string, sink: TurnSink, signal: AbortSignal): Promise<string> {
95 const store = getSessionStore();
96 const model = this.modelFor(convKey);
97 const config = model === this.deps.config.defaults.model
98 ? this.deps.config
99 : { ...this.deps.config, defaults: { ...this.deps.config.defaults, model } }; // per-chat model override
100 // Resolve (or create) the durable session FIRST so the AgentLoop is born
101 // with that session's cwd — not the directory the bot process happened to
102 // start in. `/continue` binds a CLI session; tools must edit THAT project.
103 let sessionId = await this.map.get(convKey);
104 const existing = sessionId ? store.loadSession(sessionId) : null;
105 const cwd = this.cwdFor(sessionId);
106
107 const agent = new AgentLoop({
108 router: this.deps.router,
109 registry: this.deps.registry,
110 permissions: this.deps.permissions,
111 config,
112 cwd,
113 });
114
115 let messages;
116 if (existing) {
117 messages = [...existing.messages, { role: 'user' as const, content: userText }];
118 } else {
119 sessionId = store.createSession(cwd, model);
120 await this.map.set(convKey, sessionId);
121 messages = await agent.buildInitialMessages(userText, 'normal', model);
122 }
123 const sid: string = sessionId!; // always set by the branch above
124 store.recordTurn(sid, [{ role: 'user', content: userText }], { input: 0, output: 0, costUsd: 0 });
125
126 // /auto on → approve permission prompts automatically (skip the buttons) for the affirmative
127 // option only; a prompt with no clear "yes/allow" still falls back to asking, so we never
128 // silently green-light something ambiguous.
129 const auto = this.autoByKey.get(convKey) ?? false;
130 const askUser = async (prompt: string, options: string[] = ['yes', 'no']): Promise<string> => {
131 if (auto) { const yes = options.find(o => /^(y|yes|allow|approve|ok|always)\b/i.test(o.trim())); if (yes) return yes; }
132 return getOperatorHub().requestApproval('bot', prompt, options, {
133 lane: botLane(convKey),
134 origin: convKey,
135 });
136 };
137

Callers

nothing calls this directly

Calls 15

modelForMethod · 0.95
buildInitialMessagesMethod · 0.95
runMethod · 0.95
pushMethod · 0.95
flushMethod · 0.95
getSessionStoreFunction · 0.85
dedupeSelfRepeatedTextFunction · 0.85
loadSessionMethod · 0.80
createSessionMethod · 0.80
recordTurnMethod · 0.80
onDeltaMethod · 0.80

Tested by

no test coverage detected