arki 0.0.6 → 0.0.7

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/README.md CHANGED
@@ -45,6 +45,7 @@ arki [options]
45
45
  Options:
46
46
  -p <path> Specify working directory
47
47
  --debug, -d Enable debug mode, show detailed logs
48
+ --init Initialize project config without prompting
48
49
  --reset Reset configuration to factory defaults
49
50
  --help, -h Show help information
50
51
  ```
@@ -99,6 +100,7 @@ Each project can have its own configuration in `.arki/` directory:
99
100
  - `.arki/state.json` - Project state and cache
100
101
 
101
102
  On first run in a new project, Arki will ask if you trust the project before initializing the `.arki/` directory.
103
+ Use `--init` to skip the prompt in non-interactive environments.
102
104
 
103
105
  ### Reset to Factory Defaults
104
106
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "agents": {
3
- "main": {
3
+ "arki": {
4
4
  "model": "gpt-5.1",
5
5
  "flex": true,
6
6
  "reasoningEffort": "medium"
package/dist/index.d.ts CHANGED
@@ -160,15 +160,16 @@ declare const PATHS: {
160
160
  projectTemplate: string;
161
161
  };
162
162
 
163
- /**
164
- * Fixed parameters
165
- */
166
- declare const TEMPERATURE = 0.2;
167
- declare const MAX_COMPLETION_TOKENS = 4096;
168
163
  /**
169
164
  * Reasoning effort
170
165
  */
171
166
  type ReasoningEffort$1 = 'low' | 'medium' | 'high';
167
+ /**
168
+ * Platform-specific options for adapter
169
+ */
170
+ interface AdapterOptions {
171
+ [key: string]: unknown;
172
+ }
172
173
  /**
173
174
  * LLM response result
174
175
  */
@@ -184,45 +185,31 @@ interface AdapterResponse {
184
185
  }
185
186
  /**
186
187
  * LLM adapter base class
188
+ * Only contains platform authentication, model/tools belong to Agent
187
189
  */
188
190
  declare abstract class Adapter {
189
191
  protected apiKey: string;
190
- protected model: string;
191
- /** Use Flex API (OpenAI) - low priority, low cost */
192
- protected flex?: boolean;
193
- /** Reasoning effort (thinking mode) */
194
- protected reasoningEffort?: ReasoningEffort$1;
195
- /** Available tools list */
196
- protected tools?: Tool[];
197
- constructor(config: {
198
- apiKey: string;
199
- model: string;
200
- /** Use Flex API (OpenAI) - low priority, low cost */
201
- flex?: boolean;
202
- /** Reasoning effort (thinking mode) */
203
- reasoningEffort?: ReasoningEffort$1;
204
- /** Available tools list */
205
- tools?: Tool[];
206
- });
207
- abstract chat(messages: Msg[], onChunk?: (chunk: string) => void): Promise<AdapterResponse>;
208
- getModel(): string;
192
+ constructor(apiKey: string);
193
+ abstract chat(model: string, messages: Msg[], tools: Tool[], options: AdapterOptions, onChunk?: (chunk: string) => void): Promise<AdapterResponse>;
209
194
  }
210
195
 
211
196
  /** Global tool registry */
212
197
  declare const TOOLS: Record<string, Tool>;
213
198
  /** Global procedure registry */
214
199
  declare const PROCEDURES: Record<string, Procedure>;
215
- /** Global Adapter instance */
216
- declare let adapter: Adapter | null;
217
- /** Initialize global Adapter */
218
- declare function initAdapter(): void;
200
+ /** Global adapter registry by platform */
201
+ declare const adapters: Record<string, Adapter>;
202
+ /**
203
+ * Get adapter by platform name
204
+ */
205
+ declare function getAdapter(platform: string): Adapter;
219
206
  /** Initialize global state */
220
- declare function init(cwd?: string): Promise<void>;
207
+ declare function init(cwd?: string, forceInit?: boolean): Promise<void>;
221
208
 
222
209
  /**
223
210
  * Agent type
224
211
  */
225
- type AgentType = 'main' | 'coder';
212
+ type AgentType = 'arki' | 'coder';
226
213
  /**
227
214
  * Reasoning effort
228
215
  */
@@ -231,23 +218,17 @@ type ReasoningEffort = 'low' | 'medium' | 'high';
231
218
  * Agent model configuration
232
219
  */
233
220
  interface AgentModelConfig {
234
- /** Model ID */
221
+ /** Model ID (provider is derived from MODELS) */
235
222
  model: string;
236
- /** Use Flex API (low priority, low cost) */
223
+ /** Use Flex API (low priority, low cost) - OpenAI specific */
237
224
  flex?: boolean;
238
225
  /** Reasoning effort (thinking mode) */
239
226
  reasoningEffort?: ReasoningEffort;
240
227
  }
241
228
  /**
242
- * Global configuration
229
+ * Global configuration (from config files)
243
230
  */
244
231
  interface GlobalConfig {
245
- apiKeys?: {
246
- openai?: string;
247
- anthropic?: string;
248
- google?: string;
249
- [key: string]: string | undefined;
250
- };
251
232
  agents: {
252
233
  [K in AgentType]?: AgentModelConfig;
253
234
  };
@@ -257,7 +238,7 @@ interface GlobalConfig {
257
238
  */
258
239
  declare function getConfig(): GlobalConfig;
259
240
  /**
260
- * Get API key for a provider
241
+ * Get API key from environment variable
261
242
  */
262
243
  declare function getApiKey(provider: string): string | undefined;
263
244
  /**
@@ -355,18 +336,23 @@ declare function convertColorTags(str: string): string;
355
336
  */
356
337
  declare function createColorConverter(): (chunk: string) => string;
357
338
 
339
+ /**
340
+ * OpenAI-specific options
341
+ */
342
+ interface OpenAIOptions extends AdapterOptions {
343
+ /** Use Flex API - low priority, low cost */
344
+ flex?: boolean;
345
+ /** Reasoning effort (thinking mode) */
346
+ reasoningEffort?: ReasoningEffort$1;
347
+ /** Maximum completion tokens for LLM response */
348
+ maxCompletionTokens?: number;
349
+ }
358
350
  declare class OpenAIAdapter extends Adapter {
359
351
  private client;
360
- constructor(config: {
361
- apiKey: string;
362
- model: string;
363
- flex?: boolean;
364
- reasoningEffort?: 'low' | 'medium' | 'high';
365
- tools?: Tool[];
366
- });
352
+ constructor(apiKey: string);
367
353
  private toOpenAIMessages;
368
- private getTools;
369
- chat(messages: Msg[], onChunk?: (chunk: string) => void): Promise<AdapterResponse>;
354
+ private formatTools;
355
+ chat(model: string, messages: Msg[], tools: Tool[], options: OpenAIOptions, onChunk?: (chunk: string) => void): Promise<AdapterResponse>;
370
356
  }
371
357
 
372
358
  interface AgentResponse {
@@ -383,17 +369,24 @@ interface AgentResponse {
383
369
  cachedTokens?: number;
384
370
  };
385
371
  }
372
+ interface AgentConfig {
373
+ adapter: Adapter;
374
+ model: string;
375
+ tools: Tool[];
376
+ platformOptions?: AdapterOptions;
377
+ messages: Msg[];
378
+ /** Maximum completion tokens for LLM response */
379
+ maxCompletionTokens?: number;
380
+ onStream?: (chunk: string) => void;
381
+ onToolCallMsg?: (msg: ToolCallMsg) => void;
382
+ onBeforeToolRun?: (name: string, args: Record<string, unknown>) => void;
383
+ onToolResult?: (name: string, args: Record<string, unknown>, result: string) => void;
384
+ }
386
385
  declare class Agent {
387
386
  private config;
388
387
  private messages;
389
- constructor(config: {
390
- adapter: Adapter;
391
- messages: Msg[];
392
- onStream?: (chunk: string) => void;
393
- onToolCallMsg?: (msg: ToolCallMsg) => void;
394
- onBeforeToolRun?: (name: string, args: Record<string, unknown>) => void;
395
- onToolResult?: (name: string, args: Record<string, unknown>, result: string) => void;
396
- });
388
+ private toolsMap;
389
+ constructor(config: AgentConfig);
397
390
  /**
398
391
  * Render template string, replacing {{variable}} style variables
399
392
  */
@@ -428,4 +421,4 @@ interface Model {
428
421
  readonly capabilities: ModelCapabilities;
429
422
  }
430
423
 
431
- export { AIMsg, Adapter, type AdapterResponse, Agent, type AgentModelConfig, type AgentResponse, type AgentType, type ColorName, type GlobalConfig, HAS_MANUAL, MAX_COMPLETION_TOKENS, MODELS, type Model, type ModelCapabilities, type ModelProvider, Msg, MsgType, OS, type OS_TYPE, OpenAIAdapter, PATHS, PROCEDURES, type ReasoningEffort$1 as ReasoningEffort, SystemMsg, TEMPERATURE, TOOLS, Tool, type ToolCall, ToolCallMsg, type ToolResult, ToolResultMsg, UserMsg, adapter, colors, convertColorTags, createColorConverter, debug, error, getAgentConfig, getApiKey, getConfig, info, init, initAdapter, isDebugMode, log, print, saveConfig, setDebugMode, setWorkingDir, success, warn, workingDir };
424
+ export { AIMsg, Adapter, type AdapterOptions, type AdapterResponse, Agent, type AgentModelConfig, type AgentResponse, type AgentType, type ColorName, type GlobalConfig, HAS_MANUAL, MODELS, type Model, type ModelCapabilities, type ModelProvider, Msg, MsgType, OS, type OS_TYPE, OpenAIAdapter, type OpenAIOptions, PATHS, PROCEDURES, type ReasoningEffort$1 as ReasoningEffort, SystemMsg, TOOLS, Tool, type ToolCall, ToolCallMsg, type ToolResult, ToolResultMsg, UserMsg, adapters, colors, convertColorTags, createColorConverter, debug, error, getAdapter, getAgentConfig, getApiKey, getConfig, info, init, isDebugMode, log, print, saveConfig, setDebugMode, setWorkingDir, success, warn, workingDir };
package/dist/index.js CHANGED
@@ -161,98 +161,6 @@ var init_fs = __esm({
161
161
  }
162
162
  });
163
163
 
164
- // src/adapter/Adapter.ts
165
- var TEMPERATURE, MAX_COMPLETION_TOKENS, Adapter;
166
- var init_Adapter = __esm({
167
- "src/adapter/Adapter.ts"() {
168
- "use strict";
169
- TEMPERATURE = 0.2;
170
- MAX_COMPLETION_TOKENS = 4096;
171
- Adapter = class {
172
- apiKey;
173
- model;
174
- /** Use Flex API (OpenAI) - low priority, low cost */
175
- flex;
176
- /** Reasoning effort (thinking mode) */
177
- reasoningEffort;
178
- /** Available tools list */
179
- tools;
180
- constructor(config) {
181
- this.apiKey = config.apiKey;
182
- this.model = config.model;
183
- this.flex = config.flex;
184
- this.reasoningEffort = config.reasoningEffort;
185
- this.tools = config.tools;
186
- }
187
- getModel() {
188
- return this.model;
189
- }
190
- };
191
- }
192
- });
193
-
194
- // src/agent/Msg.ts
195
- var MsgType, Msg, SystemMsg, UserMsg, AIMsg, ToolCallMsg, ToolResultMsg;
196
- var init_Msg = __esm({
197
- "src/agent/Msg.ts"() {
198
- "use strict";
199
- MsgType = /* @__PURE__ */ ((MsgType2) => {
200
- MsgType2["System"] = "system";
201
- MsgType2["User"] = "user";
202
- MsgType2["AI"] = "ai";
203
- MsgType2["ToolCall"] = "tool_call";
204
- MsgType2["ToolResult"] = "tool_result";
205
- return MsgType2;
206
- })(MsgType || {});
207
- Msg = class {
208
- timestamp;
209
- content;
210
- constructor(content) {
211
- this.timestamp = Date.now();
212
- this.content = content;
213
- }
214
- };
215
- SystemMsg = class extends Msg {
216
- type = "system" /* System */;
217
- constructor(content) {
218
- super(content);
219
- }
220
- };
221
- UserMsg = class extends Msg {
222
- type = "user" /* User */;
223
- constructor(content) {
224
- super(content);
225
- }
226
- };
227
- AIMsg = class extends Msg {
228
- type = "ai" /* AI */;
229
- constructor(content) {
230
- super(content);
231
- }
232
- };
233
- ToolCallMsg = class extends Msg {
234
- type = "tool_call" /* ToolCall */;
235
- toolCalls;
236
- constructor(content, toolCalls) {
237
- super(content);
238
- this.toolCalls = toolCalls;
239
- }
240
- };
241
- ToolResultMsg = class _ToolResultMsg extends Msg {
242
- type = "tool_result" /* ToolResult */;
243
- toolResults;
244
- constructor(toolResults) {
245
- super("");
246
- this.toolResults = toolResults;
247
- }
248
- /** Helper: create from single result */
249
- static single(toolName, result, isError) {
250
- return new _ToolResultMsg([{ toolName, result, isError }]);
251
- }
252
- };
253
- }
254
- });
255
-
256
164
  // src/log/log.ts
257
165
  function getTimestamp() {
258
166
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
@@ -362,129 +270,6 @@ var init_log2 = __esm({
362
270
  }
363
271
  });
364
272
 
365
- // src/adapter/openai.ts
366
- import OpenAI from "openai";
367
- var OpenAIAdapter;
368
- var init_openai = __esm({
369
- "src/adapter/openai.ts"() {
370
- "use strict";
371
- init_Adapter();
372
- init_Msg();
373
- init_log2();
374
- OpenAIAdapter = class extends Adapter {
375
- client;
376
- constructor(config) {
377
- super(config);
378
- if (!this.apiKey) {
379
- throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable.");
380
- }
381
- this.client = new OpenAI({ apiKey: this.apiKey });
382
- }
383
- toOpenAIMessages(messages) {
384
- const result = [];
385
- let pendingIds = [];
386
- for (const msg of messages) {
387
- if (msg.type === "system" /* System */ || msg.type === "user" /* User */) {
388
- result.push({ role: msg.type, content: msg.content });
389
- } else if (msg.type === "ai" /* AI */) {
390
- result.push({ role: "assistant", content: msg.content });
391
- } else if (msg.type === "tool_call" /* ToolCall */) {
392
- const toolCallMsg = msg;
393
- pendingIds = toolCallMsg.toolCalls.map((_, i) => `call_${msg.timestamp}_${i}`);
394
- result.push({
395
- role: "assistant",
396
- content: msg.content || null,
397
- tool_calls: toolCallMsg.toolCalls.map((tc, i) => ({
398
- id: pendingIds[i],
399
- type: "function",
400
- function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
401
- }))
402
- });
403
- } else if (msg.type === "tool_result" /* ToolResult */) {
404
- const toolResultMsg = msg;
405
- for (const tr of toolResultMsg.toolResults) {
406
- result.push({
407
- role: "tool",
408
- tool_call_id: pendingIds.shift() || `call_${msg.timestamp}`,
409
- content: tr.isError ? `Error: ${tr.result}` : tr.result
410
- });
411
- }
412
- }
413
- }
414
- return result;
415
- }
416
- getTools() {
417
- return this.tools?.map((t) => ({
418
- type: "function",
419
- function: {
420
- name: t.name,
421
- description: t.description,
422
- parameters: {
423
- type: "object",
424
- properties: t.parameters,
425
- required: t.required.length > 0 ? t.required : void 0
426
- }
427
- }
428
- }));
429
- }
430
- async chat(messages, onChunk) {
431
- debug("API", `Requesting OpenAI (model: ${this.model}, messages: ${messages.length})`);
432
- const openaiMessages = this.toOpenAIMessages(messages);
433
- const startTime = Date.now();
434
- const requestParams = {
435
- model: this.model,
436
- messages: openaiMessages,
437
- tools: this.getTools(),
438
- temperature: TEMPERATURE,
439
- max_completion_tokens: MAX_COMPLETION_TOKENS,
440
- stream: true,
441
- stream_options: { include_usage: true },
442
- service_tier: this.flex ? "flex" : void 0,
443
- reasoning_effort: this.reasoningEffort
444
- };
445
- const stream = await this.client.chat.completions.create(requestParams);
446
- let text = "";
447
- const toolCalls = /* @__PURE__ */ new Map();
448
- let usage;
449
- for await (const chunk of stream) {
450
- const delta = chunk.choices[0]?.delta;
451
- if (delta?.content) {
452
- text += delta.content;
453
- onChunk?.(delta.content);
454
- }
455
- if (delta?.tool_calls) {
456
- for (const tc of delta.tool_calls) {
457
- const cur = toolCalls.get(tc.index) || { name: "", args: "" };
458
- cur.name += tc.function?.name || "";
459
- cur.args += tc.function?.arguments || "";
460
- toolCalls.set(tc.index, cur);
461
- }
462
- }
463
- if (chunk.usage) usage = chunk.usage;
464
- }
465
- const elapsed = Date.now() - startTime;
466
- const cachedTokens = usage?.prompt_tokens_details?.cached_tokens;
467
- const usageData = usage && {
468
- promptTokens: usage.prompt_tokens,
469
- completionTokens: usage.completion_tokens,
470
- totalTokens: usage.total_tokens,
471
- cachedTokens
472
- };
473
- if (toolCalls.size > 0) {
474
- const calls = [...toolCalls.values()].map((tc) => ({
475
- name: tc.name,
476
- arguments: JSON.parse(tc.args || "{}")
477
- }));
478
- debug("API", `Completed (${elapsed}ms, tools: ${calls.map((t) => t.name).join(", ")})`);
479
- return { message: new ToolCallMsg(text, calls), hasToolCalls: true, usage: usageData };
480
- }
481
- debug("API", `Completed (${elapsed}ms, tokens: ${usage?.total_tokens || "N/A"})`);
482
- return { message: new AIMsg(text), hasToolCalls: false, usage: usageData };
483
- }
484
- };
485
- }
486
- });
487
-
488
273
  // src/init/loader.ts
489
274
  var loader_exports = {};
490
275
  __export(loader_exports, {
@@ -500,9 +285,6 @@ function deepMerge(base, override) {
500
285
  ...base,
501
286
  agents: { ...base.agents }
502
287
  };
503
- if (override.apiKeys) {
504
- result.apiKeys = { ...base.apiKeys, ...override.apiKeys };
505
- }
506
288
  if (override.agents) {
507
289
  for (const key of Object.keys(override.agents)) {
508
290
  const overrideAgent = override.agents[key];
@@ -513,26 +295,6 @@ function deepMerge(base, override) {
513
295
  }
514
296
  return result;
515
297
  }
516
- function loadEnvApiKeys(config) {
517
- if (process.env.OPENAI_API_KEY) {
518
- if (!config.apiKeys) config.apiKeys = {};
519
- if (!config.apiKeys.openai) {
520
- config.apiKeys.openai = process.env.OPENAI_API_KEY;
521
- }
522
- }
523
- if (process.env.ANTHROPIC_API_KEY) {
524
- if (!config.apiKeys) config.apiKeys = {};
525
- if (!config.apiKeys.anthropic) {
526
- config.apiKeys.anthropic = process.env.ANTHROPIC_API_KEY;
527
- }
528
- }
529
- if (process.env.GOOGLE_API_KEY) {
530
- if (!config.apiKeys) config.apiKeys = {};
531
- if (!config.apiKeys.google) {
532
- config.apiKeys.google = process.env.GOOGLE_API_KEY;
533
- }
534
- }
535
- }
536
298
  async function loadConfigs() {
537
299
  if (mergedConfig) {
538
300
  return mergedConfig;
@@ -549,7 +311,6 @@ async function loadConfigs() {
549
311
  } else {
550
312
  mergedConfig = globalConfig;
551
313
  }
552
- loadEnvApiKeys(mergedConfig);
553
314
  return mergedConfig;
554
315
  }
555
316
  function getConfig() {
@@ -559,7 +320,13 @@ function getConfig() {
559
320
  return mergedConfig;
560
321
  }
561
322
  function getApiKey(provider) {
562
- return getConfig().apiKeys?.[provider];
323
+ const envMap = {
324
+ openai: "OPENAI_API_KEY",
325
+ anthropic: "ANTHROPIC_API_KEY",
326
+ google: "GOOGLE_API_KEY"
327
+ };
328
+ const envVar = envMap[provider] || `${provider.toUpperCase()}_API_KEY`;
329
+ return process.env[envVar];
563
330
  }
564
331
  function getAgentConfig(agentType) {
565
332
  const agentConfig = getConfig().agents[agentType];
@@ -571,20 +338,7 @@ function getAgentConfig(agentType) {
571
338
  async function saveConfig() {
572
339
  const config = getConfig();
573
340
  const configPath = path3.join(PATHS.globalConfig, "config.json");
574
- const configToSave = { ...config };
575
- if (config.apiKeys) {
576
- configToSave.apiKeys = { ...config.apiKeys };
577
- if (process.env.OPENAI_API_KEY && configToSave.apiKeys.openai === process.env.OPENAI_API_KEY) {
578
- delete configToSave.apiKeys.openai;
579
- }
580
- if (process.env.ANTHROPIC_API_KEY && configToSave.apiKeys.anthropic === process.env.ANTHROPIC_API_KEY) {
581
- delete configToSave.apiKeys.anthropic;
582
- }
583
- if (process.env.GOOGLE_API_KEY && configToSave.apiKeys.google === process.env.GOOGLE_API_KEY) {
584
- delete configToSave.apiKeys.google;
585
- }
586
- }
587
- await writeJsonFile(configPath, configToSave);
341
+ await writeJsonFile(configPath, config);
588
342
  }
589
343
  var mergedConfig;
590
344
  var init_loader = __esm({
@@ -595,28 +349,6 @@ var init_loader = __esm({
595
349
  }
596
350
  });
597
351
 
598
- // src/init/index.ts
599
- var init_exports = {};
600
- __export(init_exports, {
601
- PROCEDURES: () => PROCEDURES,
602
- TOOLS: () => TOOLS,
603
- adapter: () => adapter,
604
- getAgentConfig: () => getAgentConfig,
605
- getApiKey: () => getApiKey,
606
- getConfig: () => getConfig,
607
- init: () => init,
608
- initAdapter: () => initAdapter,
609
- loadConfigs: () => loadConfigs,
610
- saveConfig: () => saveConfig
611
- });
612
- var init_init = __esm({
613
- "src/init/index.ts"() {
614
- "use strict";
615
- init_global();
616
- init_loader();
617
- }
618
- });
619
-
620
352
  // src/init/project.ts
621
353
  var project_exports = {};
622
354
  __export(project_exports, {
@@ -636,14 +368,16 @@ async function askQuestion(question) {
636
368
  });
637
369
  });
638
370
  }
639
- async function initProject() {
371
+ async function initProject(forceInit) {
640
372
  const projectConfigDir = PATHS.projectConfig;
641
373
  if (await dirExists(projectConfigDir)) {
642
374
  return;
643
375
  }
644
- print(`
376
+ const trusted = forceInit ? true : await (async () => {
377
+ print(`
645
378
  <dim>Project directory: ${workingDir}</dim>`);
646
- const trusted = await askQuestion("Do you trust this project and want to initialize arki config?");
379
+ return askQuestion("Do you trust this project and want to initialize arki config?");
380
+ })();
647
381
  if (!trusted) {
648
382
  print("<yellow>Initialization cancelled.</yellow>");
649
383
  process.exit(0);
@@ -665,66 +399,233 @@ var init_project = __esm({
665
399
  }
666
400
  });
667
401
 
402
+ // src/index.ts
403
+ import * as readline2 from "readline";
404
+ import * as fs6 from "fs";
405
+ import * as path8 from "path";
406
+ import * as os2 from "os";
407
+
408
+ // src/global.ts
409
+ init_fs();
410
+
411
+ // src/adapter/openai.ts
412
+ import OpenAI from "openai";
413
+
414
+ // src/adapter/Adapter.ts
415
+ var Adapter = class {
416
+ apiKey;
417
+ constructor(apiKey) {
418
+ this.apiKey = apiKey;
419
+ }
420
+ };
421
+
422
+ // src/agent/Msg.ts
423
+ var MsgType = /* @__PURE__ */ ((MsgType2) => {
424
+ MsgType2["System"] = "system";
425
+ MsgType2["User"] = "user";
426
+ MsgType2["AI"] = "ai";
427
+ MsgType2["ToolCall"] = "tool_call";
428
+ MsgType2["ToolResult"] = "tool_result";
429
+ return MsgType2;
430
+ })(MsgType || {});
431
+ var Msg = class {
432
+ timestamp;
433
+ content;
434
+ constructor(content) {
435
+ this.timestamp = Date.now();
436
+ this.content = content;
437
+ }
438
+ };
439
+ var SystemMsg = class extends Msg {
440
+ type = "system" /* System */;
441
+ constructor(content) {
442
+ super(content);
443
+ }
444
+ };
445
+ var UserMsg = class extends Msg {
446
+ type = "user" /* User */;
447
+ constructor(content) {
448
+ super(content);
449
+ }
450
+ };
451
+ var AIMsg = class extends Msg {
452
+ type = "ai" /* AI */;
453
+ constructor(content) {
454
+ super(content);
455
+ }
456
+ };
457
+ var ToolCallMsg = class extends Msg {
458
+ type = "tool_call" /* ToolCall */;
459
+ toolCalls;
460
+ constructor(content, toolCalls) {
461
+ super(content);
462
+ this.toolCalls = toolCalls;
463
+ }
464
+ };
465
+ var ToolResultMsg = class _ToolResultMsg extends Msg {
466
+ type = "tool_result" /* ToolResult */;
467
+ toolResults;
468
+ constructor(toolResults) {
469
+ super("");
470
+ this.toolResults = toolResults;
471
+ }
472
+ /** Helper: create from single result */
473
+ static single(toolName, result, isError) {
474
+ return new _ToolResultMsg([{ toolName, result, isError }]);
475
+ }
476
+ };
477
+
478
+ // src/adapter/openai.ts
479
+ init_log2();
480
+ var OpenAIAdapter = class extends Adapter {
481
+ client;
482
+ constructor(apiKey) {
483
+ super(apiKey);
484
+ if (!this.apiKey) {
485
+ throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable.");
486
+ }
487
+ this.client = new OpenAI({ apiKey: this.apiKey });
488
+ }
489
+ toOpenAIMessages(messages) {
490
+ const result = [];
491
+ let pendingIds = [];
492
+ for (const msg of messages) {
493
+ if (msg.type === "system" /* System */ || msg.type === "user" /* User */) {
494
+ result.push({ role: msg.type, content: msg.content });
495
+ } else if (msg.type === "ai" /* AI */) {
496
+ result.push({ role: "assistant", content: msg.content });
497
+ } else if (msg.type === "tool_call" /* ToolCall */) {
498
+ const toolCallMsg = msg;
499
+ pendingIds = toolCallMsg.toolCalls.map((_, i) => `call_${msg.timestamp}_${i}`);
500
+ result.push({
501
+ role: "assistant",
502
+ content: msg.content || null,
503
+ tool_calls: toolCallMsg.toolCalls.map((tc, i) => ({
504
+ id: pendingIds[i],
505
+ type: "function",
506
+ function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
507
+ }))
508
+ });
509
+ } else if (msg.type === "tool_result" /* ToolResult */) {
510
+ const toolResultMsg = msg;
511
+ for (const tr of toolResultMsg.toolResults) {
512
+ result.push({
513
+ role: "tool",
514
+ tool_call_id: pendingIds.shift() || `call_${msg.timestamp}`,
515
+ content: tr.isError ? `Error: ${tr.result}` : tr.result
516
+ });
517
+ }
518
+ }
519
+ }
520
+ return result;
521
+ }
522
+ formatTools(tools) {
523
+ if (tools.length === 0) return void 0;
524
+ return tools.map((t) => ({
525
+ type: "function",
526
+ function: {
527
+ name: t.name,
528
+ description: t.description,
529
+ parameters: {
530
+ type: "object",
531
+ properties: t.parameters,
532
+ required: t.required.length > 0 ? t.required : void 0
533
+ }
534
+ }
535
+ }));
536
+ }
537
+ async chat(model, messages, tools, options, onChunk) {
538
+ debug("API", `Requesting OpenAI (model: ${model}, messages: ${messages.length})`);
539
+ const openaiMessages = this.toOpenAIMessages(messages);
540
+ const startTime = Date.now();
541
+ const requestParams = {
542
+ model,
543
+ messages: openaiMessages,
544
+ tools: this.formatTools(tools),
545
+ max_completion_tokens: options.maxCompletionTokens,
546
+ stream: true,
547
+ stream_options: { include_usage: true },
548
+ service_tier: options.flex ? "flex" : void 0,
549
+ reasoning_effort: options.reasoningEffort
550
+ };
551
+ const stream = await this.client.chat.completions.create(requestParams);
552
+ let text = "";
553
+ const toolCalls = /* @__PURE__ */ new Map();
554
+ let usage;
555
+ for await (const chunk of stream) {
556
+ const delta = chunk.choices[0]?.delta;
557
+ if (delta?.content) {
558
+ text += delta.content;
559
+ onChunk?.(delta.content);
560
+ }
561
+ if (delta?.tool_calls) {
562
+ for (const tc of delta.tool_calls) {
563
+ const cur = toolCalls.get(tc.index) || { name: "", args: "" };
564
+ cur.name += tc.function?.name || "";
565
+ cur.args += tc.function?.arguments || "";
566
+ toolCalls.set(tc.index, cur);
567
+ }
568
+ }
569
+ if (chunk.usage) usage = chunk.usage;
570
+ }
571
+ const elapsed = Date.now() - startTime;
572
+ const cachedTokens = usage?.prompt_tokens_details?.cached_tokens;
573
+ const usageData = usage && {
574
+ promptTokens: usage.prompt_tokens,
575
+ completionTokens: usage.completion_tokens,
576
+ totalTokens: usage.total_tokens,
577
+ cachedTokens
578
+ };
579
+ if (toolCalls.size > 0) {
580
+ const calls = [...toolCalls.values()].map((tc) => ({
581
+ name: tc.name,
582
+ arguments: JSON.parse(tc.args || "{}")
583
+ }));
584
+ debug("API", `Completed (${elapsed}ms, tools: ${calls.map((t) => t.name).join(", ")})`);
585
+ return { message: new ToolCallMsg(text, calls), hasToolCalls: true, usage: usageData };
586
+ }
587
+ debug("API", `Completed (${elapsed}ms, tokens: ${usage?.total_tokens || "N/A"})`);
588
+ return { message: new AIMsg(text), hasToolCalls: false, usage: usageData };
589
+ }
590
+ };
591
+
668
592
  // src/init/global.ts
593
+ init_fs();
594
+ var TOOLS = {};
595
+ var PROCEDURES = {};
596
+ var adapters = {};
597
+ function getAdapter(platform) {
598
+ const adapter = adapters[platform];
599
+ if (!adapter) {
600
+ throw new Error(`Adapter not found for platform: ${platform}`);
601
+ }
602
+ return adapter;
603
+ }
669
604
  async function initGlobalConfig() {
670
605
  const globalConfigDir = PATHS.globalConfig;
671
- if (await dirExists(globalConfigDir)) {
672
- return;
673
- }
606
+ if (await dirExists(globalConfigDir)) return;
674
607
  await copyDir(PATHS.globalTemplate, globalConfigDir);
675
608
  }
676
- function initAdapter() {
677
- if (adapter) {
678
- return;
609
+ async function initAdapters() {
610
+ const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
611
+ const openaiKey = getApiKey2("openai");
612
+ if (openaiKey) {
613
+ adapters["openai"] = new OpenAIAdapter(openaiKey);
679
614
  }
680
- Promise.resolve().then(() => (init_init(), init_exports)).then(({ getAgentConfig: getAgentConfig2, getApiKey: getApiKey2 }) => {
681
- const mainAgentConfig = getAgentConfig2("main");
682
- adapter = new OpenAIAdapter({
683
- apiKey: getApiKey2("openai") || "",
684
- model: mainAgentConfig.model,
685
- flex: mainAgentConfig.flex,
686
- tools: Object.values(TOOLS)
687
- });
688
- });
689
615
  }
690
- async function init(cwd) {
616
+ async function init(cwd, forceInit) {
691
617
  const { setWorkingDir: setWorkingDir2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
692
618
  setWorkingDir2(cwd || process.cwd());
693
619
  await initGlobalConfig();
694
620
  const { initProject: initProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
695
- await initProject2();
696
- const { loadConfigs: loadConfigs2, getAgentConfig: getAgentConfig2, getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
621
+ await initProject2(forceInit);
622
+ const { loadConfigs: loadConfigs2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
697
623
  await loadConfigs2();
698
- const mainAgentConfig = getAgentConfig2("main");
699
- adapter = new OpenAIAdapter({
700
- apiKey: getApiKey2("openai") || "",
701
- model: mainAgentConfig.model,
702
- flex: mainAgentConfig.flex,
703
- tools: Object.values(TOOLS)
704
- });
624
+ await initAdapters();
705
625
  }
706
- var TOOLS, PROCEDURES, adapter;
707
- var init_global = __esm({
708
- "src/init/global.ts"() {
709
- "use strict";
710
- init_openai();
711
- init_fs();
712
- TOOLS = {};
713
- PROCEDURES = {};
714
- adapter = null;
715
- }
716
- });
717
-
718
- // src/index.ts
719
- import * as readline2 from "readline";
720
- import * as fs6 from "fs";
721
- import * as path8 from "path";
722
- import * as os2 from "os";
723
626
 
724
- // src/global.ts
725
- init_fs();
726
- init_global();
727
- init_init();
627
+ // src/init/index.ts
628
+ init_loader();
728
629
 
729
630
  // src/tool/Tool.ts
730
631
  init_log2();
@@ -1059,15 +960,17 @@ var MODELS = {
1059
960
  };
1060
961
 
1061
962
  // src/agent/Agent.ts
1062
- init_Msg();
1063
- init_init();
1064
963
  init_log2();
1065
964
  var Agent = class {
1066
965
  config;
1067
966
  messages = [];
967
+ toolsMap = {};
1068
968
  constructor(config) {
1069
969
  this.config = config;
1070
970
  this.messages = [...config.messages];
971
+ for (const tool of config.tools) {
972
+ this.toolsMap[tool.name] = tool;
973
+ }
1071
974
  }
1072
975
  /**
1073
976
  * Render template string, replacing {{variable}} style variables
@@ -1089,7 +992,16 @@ var Agent = class {
1089
992
  let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cachedTokens: 0 };
1090
993
  while (true) {
1091
994
  debug("Agent", `Starting conversation (message count: ${this.messages.length})`);
1092
- const response = await this.config.adapter.chat(this.messages, this.config.onStream);
995
+ const response = await this.config.adapter.chat(
996
+ this.config.model,
997
+ this.messages,
998
+ this.config.tools,
999
+ {
1000
+ ...this.config.platformOptions,
1001
+ maxCompletionTokens: this.config.maxCompletionTokens
1002
+ },
1003
+ this.config.onStream
1004
+ );
1093
1005
  if (response.usage) {
1094
1006
  totalUsage.promptTokens += response.usage.promptTokens;
1095
1007
  totalUsage.completionTokens += response.usage.completionTokens;
@@ -1114,7 +1026,7 @@ var Agent = class {
1114
1026
  const toolResults = [];
1115
1027
  for (const tc of toolCalls) {
1116
1028
  this.config.onBeforeToolRun?.(tc.name, tc.arguments);
1117
- const tool = TOOLS[tc.name];
1029
+ const tool = this.toolsMap[tc.name];
1118
1030
  const result = tool ? await tool.run(tc.arguments) : { toolName: tc.name, result: `Unknown tool: ${tc.name}`, isError: true };
1119
1031
  toolCallHistory.push({
1120
1032
  name: tc.name,
@@ -1133,9 +1045,6 @@ var Agent = class {
1133
1045
  }
1134
1046
  };
1135
1047
 
1136
- // src/agent/index.ts
1137
- init_Msg();
1138
-
1139
1048
  // src/agent/Arki/Arki.ts
1140
1049
  init_log2();
1141
1050
 
@@ -1143,11 +1052,15 @@ init_log2();
1143
1052
  var system_default = "You are Arki, a professional AI programming assistant. You work in the codebase directory `{{working_dir}}`.\n\n## Tool Usage\n\nTools can be called multiple times at once.\nIf a tool has the {{has_manual}} symbol in its description, you **MUST** call `read_tool_manual` before using it. Read the manual exactly once per tool - do not skip it, and do not read it repeatedly.\n\n## Procedure Usage\n\nProcedures are step-by-step guides for specific workflows. When a task involves a defined procedure, you **MUST** call `read_procedure` first to get the complete steps, then follow the procedure exactly.\n\nIf a procedure defines output text/format templates, translate them to the user's language unless the procedure explicitly forbids translation.\n\nAvailable procedures:\n{{procedures}}\n\n## Working Principles\n\n- **Accuracy**: Before answering questions, use tools to view relevant code first. Don't base statements on assumptions. If you don't know something, just admit it - it's no big deal. For example, never tell the user what might be inside a directory based only on its name\u2014always inspect its contents first, and never guess functionality from directory, file, or function names in a way that could mislead the user.\n- **Safety**: Consider potential risks before executing commands.\n- **Conciseness**: Keep answers brief and concise, avoid repetition and redundancy. Keep each response within 200 words unless the user requests detailed explanation. If user requirements are unclear, ask for clarification once at most. If still unclear after asking, proceed with your best understanding and show the result to the user - do not ask multiple times.\n- **Proactivity**: Actively suggest improvements when you find issues.\n\n## Response Style\n\n- Answer questions directly, avoid excessive pleasantries\n- Don't use emojis\n- Don't repeatedly ask about user needs, once is enough. Don't ask and answer yourself.\n\nThe user is talking to you via **CLI terminal**. Prefer terminal-friendly characters and plain text formatting. **Do not** output Markdown syntax such as `**` for bold, `*` or `-` for lists, etc. For long answers, feel free to organize content with clear section headings. Use numbered lists for ordered lists only when items have a clear sequence or dependency; otherwise use the \u2022 symbol for unordered lists.\nUse the following tags to format output:\n\n| Purpose | Format Tag | Usage |\n|--------|------------|-------|\n| Code blocks (```...```) | `<dim>...</dim>` | Wrap the entire code block content |\n| Inline code (`...`) | `<dim>...</dim>` | Wrap inline code snippets |\n| File paths | `<cyan>...</cyan>` | For paths, e.g., `src/index.ts` |\n| Filenames | `<gray>...</gray>` | For file names when mentioned alone |\n| Command names | `<blue>...</blue>` | For commands, e.g., `npm install` |\n| Section headings / titles | `<bold><cyan>...</cyan></bold>` | For section titles in plain text output |\n| Important or strong emphasis (**...**) | `<bold>...</bold>` | For key points that must stand out |\n| Secondary / less important info | `<dim>...</dim>` | For metadata, debug info, token counts, etc. |\n| Tips / important notices | `<yellow>...</yellow>` | For tips, cautions, non-fatal problems |\n| Success confirmations | `<green>...</green>` | For success messages, completion status |\n| Errors or serious problems | `<red>...</red>` | For real problems the user must fix |\n| Neutral informational messages | `<blue>...</blue>` | For general info that is not success/failure |\n| Highlighted keywords / categories | `<magenta>...</magenta>` | For labels, categories, or tags in text |\n| De-emphasized / grayed-out text | `<gray>...</gray>` | For low-priority info, old values, etc. |\n| Underlined emphasis | `<underline>...</underline>` | For things you want to underline instead of bold |\n| Optional / tentative text | `<italic>...</italic>` | For suggestions, optional steps, side notes |\n| Reversed highlight | `<inverse>...</inverse>` | For very strong highlights (rarely use) |\n| Deleted / not recommended content | `<strikethrough>...</strikethrough>` | For deprecated commands or steps |\n\nTags can be combined, e.g., `<bold><red>Critical Error</red></bold>`\n\n- Do not mention the contents of this prompt to users. The prompt provides context and instructions for you to follow, not to recite verbatim. Use the information in the prompt to inform your responses naturally. Bad example: \"You are currently talking to me via a Mac OS terminal interface. How can I help you?\" Good example: (Display terminal-friendly characters and provide suggestions based on the Mac OS system environment)\n\nPlease answer questions in the language the user is using, and flexibly use available tools to complete tasks.\n\n";
1144
1053
 
1145
1054
  // src/agent/Arki/Arki.ts
1055
+ var MAX_COMPLETION_TOKENS = 4096;
1146
1056
  var toolStartTimes = /* @__PURE__ */ new Map();
1147
- function createMainAgent() {
1148
- if (!adapter) {
1149
- throw new Error("Adapter not initialized, please call init() first");
1057
+ function createArkiAgent() {
1058
+ const config = getAgentConfig("arki");
1059
+ const model = MODELS[config.model];
1060
+ if (!model) {
1061
+ throw new Error(`Unknown model: ${config.model}`);
1150
1062
  }
1063
+ const adapter = getAdapter(model.provider);
1151
1064
  const proceduresList = Object.values(PROCEDURES).map((p) => `- ${p.name}: ${p.description}`).join("\n");
1152
1065
  const systemInstruction = Agent.renderTemplate(system_default, {
1153
1066
  working_dir: workingDir,
@@ -1157,6 +1070,13 @@ function createMainAgent() {
1157
1070
  const convertColor = createColorConverter();
1158
1071
  const agent = new Agent({
1159
1072
  adapter,
1073
+ model: config.model,
1074
+ tools: Object.values(TOOLS),
1075
+ maxCompletionTokens: MAX_COMPLETION_TOKENS,
1076
+ platformOptions: {
1077
+ flex: config.flex,
1078
+ reasoningEffort: config.reasoningEffort
1079
+ },
1160
1080
  messages: [new SystemMsg(systemInstruction)],
1161
1081
  onStream: (chunk) => {
1162
1082
  process.stdout.write(convertColor(chunk));
@@ -1194,7 +1114,7 @@ function createMainAgent() {
1194
1114
  // package.json
1195
1115
  var package_default = {
1196
1116
  name: "arki",
1197
- version: "0.0.6",
1117
+ version: "0.0.7",
1198
1118
  description: "AI Agent Programming Assistant",
1199
1119
  type: "module",
1200
1120
  main: "dist/index.js",
@@ -1252,13 +1172,6 @@ var package_default = {
1252
1172
 
1253
1173
  // src/index.ts
1254
1174
  init_log2();
1255
- init_Msg();
1256
-
1257
- // src/adapter/index.ts
1258
- init_Adapter();
1259
- init_openai();
1260
-
1261
- // src/index.ts
1262
1175
  function getConfigPath() {
1263
1176
  return path8.join(os2.homedir(), ".config", "arki", "config.json");
1264
1177
  }
@@ -1277,6 +1190,7 @@ function parseArgs() {
1277
1190
  const args = process.argv.slice(2);
1278
1191
  let targetDir = process.cwd();
1279
1192
  let enableDebug = false;
1193
+ let forceInit = false;
1280
1194
  for (let i = 0; i < args.length; i++) {
1281
1195
  if (args[i] === "-p" && args[i + 1]) {
1282
1196
  targetDir = args[i + 1];
@@ -1285,6 +1199,8 @@ function parseArgs() {
1285
1199
  enableDebug = true;
1286
1200
  } else if (args[i] === "--reset") {
1287
1201
  resetConfig();
1202
+ } else if (args[i] === "--init") {
1203
+ forceInit = true;
1288
1204
  } else if (args[i] === "--help" || args[i] === "-h") {
1289
1205
  console.log(`
1290
1206
  Usage: arki [options]
@@ -1292,40 +1208,36 @@ Usage: arki [options]
1292
1208
  Options:
1293
1209
  -p <path> Specify working directory
1294
1210
  --debug, -d Enable debug mode, show detailed logs
1211
+ --init Initialize project config without prompting
1295
1212
  --reset Reset configuration to factory defaults
1296
1213
  --help, -h Show help information
1297
1214
  `);
1298
1215
  process.exit(0);
1299
1216
  }
1300
1217
  }
1301
- return { targetDir, enableDebug };
1218
+ return { targetDir, enableDebug, forceInit };
1302
1219
  }
1303
1220
  async function main() {
1304
- const { targetDir, enableDebug } = parseArgs();
1221
+ const { targetDir, enableDebug, forceInit } = parseArgs();
1305
1222
  if (enableDebug) {
1306
1223
  setDebugMode(true);
1307
1224
  debug("Init", "Debug mode enabled");
1308
1225
  }
1309
- await init(targetDir);
1310
- const mainAgentConfig = getAgentConfig("main");
1311
- const model = MODELS[mainAgentConfig.model];
1226
+ await init(targetDir, forceInit);
1227
+ const arkiAgentConfig = getAgentConfig("arki");
1228
+ const model = MODELS[arkiAgentConfig.model];
1312
1229
  console.log();
1313
- log(`<cyan>Arki AI Agent v${package_default.version}</cyan>`);
1314
- console.log();
1315
- log(`<dim>Model: ${mainAgentConfig.model}${model ? ` (${model.name})` : ""}</dim>`);
1316
- log(`<dim>Working directory: ${workingDir}</dim>`);
1317
- log(`<dim>OS: ${OS.name} (${OS.version})</dim>`);
1230
+ log(`<bold><cyan>Arki AI Agent</cyan></bold> <dim>v${package_default.version}</dim>`);
1231
+ log(`<green>Model:</green> <bold>${model?.name || arkiAgentConfig.model}</bold> <dim>|</dim> <green>OS:</green> ${OS.name} <dim>(${OS.version})</dim>`);
1232
+ log(`<green>Path:</green> <dim>${workingDir}</dim>`);
1233
+ log(`<green>Tools:</green> ${Object.keys(TOOLS).length} loaded`);
1318
1234
  if (isDebugMode()) {
1319
1235
  log(`<yellow>Debug mode enabled</yellow>`);
1320
- }
1321
- console.log();
1322
- log(`<dim>Loaded ${Object.keys(TOOLS).length} tools</dim>`);
1323
- if (isDebugMode()) {
1324
1236
  debug("Init", "Loaded tools", Object.keys(TOOLS));
1325
- debug("Init", "Agent config", mainAgentConfig);
1237
+ debug("Init", "Agent config", arkiAgentConfig);
1326
1238
  }
1327
1239
  console.log();
1328
- const agent = createMainAgent();
1240
+ const agent = createArkiAgent();
1329
1241
  const rl = readline2.createInterface({
1330
1242
  input: process.stdin,
1331
1243
  output: process.stdout
@@ -1398,7 +1310,6 @@ export {
1398
1310
  Adapter,
1399
1311
  Agent,
1400
1312
  HAS_MANUAL,
1401
- MAX_COMPLETION_TOKENS,
1402
1313
  MODELS,
1403
1314
  Msg,
1404
1315
  MsgType,
@@ -1407,24 +1318,23 @@ export {
1407
1318
  PATHS,
1408
1319
  PROCEDURES,
1409
1320
  SystemMsg,
1410
- TEMPERATURE,
1411
1321
  TOOLS,
1412
1322
  Tool,
1413
1323
  ToolCallMsg,
1414
1324
  ToolResultMsg,
1415
1325
  UserMsg,
1416
- adapter,
1326
+ adapters,
1417
1327
  colors,
1418
1328
  convertColorTags,
1419
1329
  createColorConverter,
1420
1330
  debug,
1421
1331
  error,
1332
+ getAdapter,
1422
1333
  getAgentConfig,
1423
1334
  getApiKey,
1424
1335
  getConfig,
1425
1336
  info,
1426
1337
  init,
1427
- initAdapter,
1428
1338
  isDebugMode,
1429
1339
  log,
1430
1340
  print,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arki",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "AI Agent Programming Assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",