@hongymagic/q 0.3.1 → 0.4.0

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.
Files changed (3) hide show
  1. package/README.md +1 -4
  2. package/dist/q.js +77 -852
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -35,7 +35,6 @@ export ANTHROPIC_API_KEY="your-key-here"
35
35
 
36
36
  ```bash
37
37
  q how do I restart docker
38
- q --stream explain git rebase
39
38
  q --copy what is a kubernetes pod
40
39
  ```
41
40
 
@@ -45,9 +44,7 @@ q --copy what is a kubernetes pod
45
44
  |--------|-------------|
46
45
  | `-p, --provider <name>` | Override the default provider |
47
46
  | `-m, --model <id>` | Override the default model |
48
- | `--stream` | Stream response as it arrives |
49
47
  | `--copy` | Copy answer to clipboard |
50
- | `--json` | Output structured JSON |
51
48
  | `-h, --help` | Show help message |
52
49
 
53
50
  ### Commands
@@ -105,7 +102,7 @@ provider_api_key_env = "PROVIDER_API_KEY"
105
102
  | `provider_slug` | Provider identifier (maps to `x-portkey-provider` header) |
106
103
  | `api_key_env` | Environment variable for Portkey API key (maps to `x-portkey-api-key` header) |
107
104
  | `provider_api_key_env` | Environment variable for underlying provider's API key (maps to `Authorization` header) |
108
- | `headers` | Additional custom headers (supports `${VAR}` interpolation) |
105
+ | `headers` | Additional custom headers (supports env var interpolation for allowlisted vars) |
109
106
 
110
107
  **Environment variables:**
111
108
 
package/dist/q.js CHANGED
@@ -13396,9 +13396,7 @@ USAGE:
13396
13396
  OPTIONS:
13397
13397
  -p, --provider <name> Override the default provider
13398
13398
  -m, --model <id> Override the default model
13399
- --stream Stream response tokens as they arrive
13400
13399
  --copy Copy answer to clipboard
13401
- --json Output structured JSON
13402
13400
  --debug Enable debug logging to stderr
13403
13401
  -h, --help Show this help message
13404
13402
  -v, --version Show version
@@ -13415,20 +13413,17 @@ CONFIG:
13415
13413
 
13416
13414
  EXAMPLES:
13417
13415
  q how do I restart docker
13418
- q --stream explain git rebase
13419
13416
  q -p openai --model gpt-4o what is recursion
13420
13417
  q config init
13421
13418
  `;
13422
- var VERSION = "0.3.1";
13419
+ var VERSION = "0.4.0";
13423
13420
  function parseCliArgs(argv = Bun.argv.slice(2)) {
13424
13421
  const { values, positionals } = parseArgs({
13425
13422
  args: argv,
13426
13423
  options: {
13427
13424
  provider: { type: "string", short: "p" },
13428
13425
  model: { type: "string", short: "m" },
13429
- stream: { type: "boolean", default: false },
13430
13426
  copy: { type: "boolean", default: false },
13431
- json: { type: "boolean", default: false },
13432
13427
  debug: { type: "boolean", default: false },
13433
13428
  help: { type: "boolean", short: "h", default: false },
13434
13429
  version: { type: "boolean", short: "v", default: false }
@@ -13439,9 +13434,7 @@ function parseCliArgs(argv = Bun.argv.slice(2)) {
13439
13434
  const options = {
13440
13435
  provider: values.provider,
13441
13436
  model: values.model,
13442
- stream: values.stream ?? false,
13443
13437
  copy: values.copy ?? false,
13444
- json: values.json ?? false,
13445
13438
  debug: values.debug ?? false,
13446
13439
  help: values.help ?? false,
13447
13440
  version: values.version ?? false
@@ -27262,14 +27255,37 @@ ${formatZodErrors(result.error)}`);
27262
27255
  return result;
27263
27256
  }
27264
27257
  static interpolate(value) {
27265
- return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
27266
- const envValue = process.env[varName];
27267
- if (envValue === undefined) {
27268
- throw new ConfigValidationError(`Environment variable '${varName}' referenced in config but not set`);
27269
- }
27270
- return envValue;
27271
- });
27272
- }
27258
+ return interpolateValue(value);
27259
+ }
27260
+ }
27261
+ var ALLOWED_INTERPOLATION_VARS = new Set([
27262
+ "ANTHROPIC_API_KEY",
27263
+ "OPENAI_API_KEY",
27264
+ "PORTKEY_API_KEY",
27265
+ "ANTHROPIC_BASE_URL",
27266
+ "OPENAI_BASE_URL",
27267
+ "PORTKEY_BASE_URL",
27268
+ "PORTKEY_PROVIDER",
27269
+ "HTTP_PROXY",
27270
+ "HTTPS_PROXY",
27271
+ "NO_PROXY",
27272
+ "HOME",
27273
+ "USER",
27274
+ "HOSTNAME"
27275
+ ]);
27276
+ function interpolateValue(value) {
27277
+ return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
27278
+ if (!ALLOWED_INTERPOLATION_VARS.has(varName)) {
27279
+ const allowedList = Array.from(ALLOWED_INTERPOLATION_VARS).join(", ");
27280
+ throw new ConfigValidationError(`Environment variable '${varName}' is not allowed for interpolation.
27281
+ ` + `Allowed variables: ${allowedList}`);
27282
+ }
27283
+ const envValue = process.env[varName];
27284
+ if (envValue === undefined) {
27285
+ throw new ConfigValidationError(`Environment variable '${varName}' referenced in config but not set`);
27286
+ }
27287
+ return envValue;
27288
+ });
27273
27289
  }
27274
27290
  async function loadConfig() {
27275
27291
  return Config.load();
@@ -27314,7 +27330,7 @@ api_key_env = "OPENAI_API_KEY"
27314
27330
  # provider_slug = "@your-org/bedrock-provider"
27315
27331
  # api_key_env = "PORTKEY_API_KEY"
27316
27332
  # provider_api_key_env = "PROVIDER_API_KEY"
27317
- # headers = { "x-custom" = "\${CUSTOM_VALUE}" }
27333
+ # headers = { "x-portkey-trace-id" = "\${HOSTNAME}" } # Only allowlisted env vars
27318
27334
 
27319
27335
  # Example: Ollama (local models)
27320
27336
  # [providers.ollama]
@@ -27424,6 +27440,12 @@ class QError2 extends Error {
27424
27440
  this.name = "QError";
27425
27441
  }
27426
27442
  }
27443
+ class UsageError2 extends QError2 {
27444
+ constructor(message) {
27445
+ super(message, 2);
27446
+ this.name = "UsageError";
27447
+ }
27448
+ }
27427
27449
  function logError2(message) {
27428
27450
  console.error(message);
27429
27451
  }
@@ -27433,19 +27455,6 @@ function logDebug2(message, debug) {
27433
27455
  }
27434
27456
  }
27435
27457
 
27436
- // src/output.ts
27437
- function formatOutput(options) {
27438
- if (options.json) {
27439
- const output = {
27440
- text: options.text,
27441
- provider: options.providerName,
27442
- model: options.modelId
27443
- };
27444
- return JSON.stringify(output, null, 2);
27445
- }
27446
- return options.text;
27447
- }
27448
-
27449
27458
  // src/env-info.ts
27450
27459
  import * as os3 from "node:os";
27451
27460
  function getEnvironmentInfo2() {
@@ -46196,6 +46205,20 @@ function createPortkeyProvider(config2, providerName, debug = false) {
46196
46205
  }
46197
46206
 
46198
46207
  // src/providers/index.ts
46208
+ var SENSITIVE_FIELD_PATTERNS = [
46209
+ "key",
46210
+ "secret",
46211
+ "token",
46212
+ "password",
46213
+ "auth",
46214
+ "credential"
46215
+ ];
46216
+ function filterSensitiveFields(config2) {
46217
+ return Object.fromEntries(Object.entries(config2).filter(([key]) => {
46218
+ const lowerKey = key.toLowerCase();
46219
+ return !SENSITIVE_FIELD_PATTERNS.some((pattern) => lowerKey.includes(pattern));
46220
+ }));
46221
+ }
46199
46222
  function resolveProvider(config2, providerOverride, modelOverride, debug = false) {
46200
46223
  const providerName = providerOverride ?? config2.default.provider;
46201
46224
  const providerConfig = config2.providers[providerName];
@@ -46203,7 +46226,7 @@ function resolveProvider(config2, providerOverride, modelOverride, debug = false
46203
46226
  throw new ProviderNotFoundError(providerName);
46204
46227
  }
46205
46228
  const modelId = modelOverride ?? config2.default.model;
46206
- logDebug(`Provider config: ${JSON.stringify(providerConfig, null, 2)}`, debug);
46229
+ logDebug(`Provider config: ${JSON.stringify(filterSensitiveFields(providerConfig), null, 2)}`, debug);
46207
46230
  const model = createModel(providerConfig, providerName, modelId, debug);
46208
46231
  return {
46209
46232
  model,
@@ -49482,18 +49505,6 @@ async function executeToolCall({
49482
49505
  }
49483
49506
  });
49484
49507
  }
49485
- function extractReasoningContent(content) {
49486
- const parts = content.filter((content2) => content2.type === "reasoning");
49487
- return parts.length === 0 ? undefined : parts.map((content2) => content2.text).join(`
49488
- `);
49489
- }
49490
- function extractTextContent(content) {
49491
- const parts = content.filter((content2) => content2.type === "text");
49492
- if (parts.length === 0) {
49493
- return;
49494
- }
49495
- return parts.map((content2) => content2.text).join("");
49496
- }
49497
49508
  var DefaultGeneratedFile = class {
49498
49509
  constructor({
49499
49510
  data,
@@ -50531,763 +50542,6 @@ var originalGenerateId = createIdGenerator({
50531
50542
  prefix: "aitxt",
50532
50543
  size: 24
50533
50544
  });
50534
- async function generateText({
50535
- model: modelArg,
50536
- tools,
50537
- toolChoice,
50538
- system,
50539
- prompt,
50540
- messages,
50541
- maxRetries: maxRetriesArg,
50542
- abortSignal,
50543
- timeout,
50544
- headers,
50545
- stopWhen = stepCountIs(1),
50546
- experimental_output,
50547
- output = experimental_output,
50548
- experimental_telemetry: telemetry,
50549
- providerOptions,
50550
- experimental_activeTools,
50551
- activeTools = experimental_activeTools,
50552
- experimental_prepareStep,
50553
- prepareStep = experimental_prepareStep,
50554
- experimental_repairToolCall: repairToolCall,
50555
- experimental_download: download2,
50556
- experimental_context,
50557
- experimental_include: include,
50558
- _internal: { generateId: generateId2 = originalGenerateId } = {},
50559
- experimental_onStart: onStart,
50560
- experimental_onStepStart: onStepStart,
50561
- experimental_onToolCallStart: onToolCallStart,
50562
- experimental_onToolCallFinish: onToolCallFinish,
50563
- onStepFinish,
50564
- onFinish,
50565
- ...settings
50566
- }) {
50567
- const model = resolveLanguageModel(modelArg);
50568
- const stopConditions = asArray(stopWhen);
50569
- const totalTimeoutMs = getTotalTimeoutMs(timeout);
50570
- const stepTimeoutMs = getStepTimeoutMs(timeout);
50571
- const stepAbortController = stepTimeoutMs != null ? new AbortController : undefined;
50572
- const mergedAbortSignal = mergeAbortSignals(abortSignal, totalTimeoutMs != null ? AbortSignal.timeout(totalTimeoutMs) : undefined, stepAbortController == null ? undefined : stepAbortController.signal);
50573
- const { maxRetries, retry } = prepareRetries({
50574
- maxRetries: maxRetriesArg,
50575
- abortSignal: mergedAbortSignal
50576
- });
50577
- const callSettings = prepareCallSettings(settings);
50578
- const headersWithUserAgent = withUserAgentSuffix(headers != null ? headers : {}, `ai/${VERSION7}`);
50579
- const baseTelemetryAttributes = getBaseTelemetryAttributes({
50580
- model,
50581
- telemetry,
50582
- headers: headersWithUserAgent,
50583
- settings: { ...callSettings, maxRetries }
50584
- });
50585
- const modelInfo = { provider: model.provider, modelId: model.modelId };
50586
- const initialPrompt = await standardizePrompt({
50587
- system,
50588
- prompt,
50589
- messages
50590
- });
50591
- try {
50592
- await (onStart == null ? undefined : onStart({
50593
- model: modelInfo,
50594
- system,
50595
- prompt,
50596
- messages,
50597
- tools,
50598
- toolChoice,
50599
- activeTools,
50600
- maxOutputTokens: callSettings.maxOutputTokens,
50601
- temperature: callSettings.temperature,
50602
- topP: callSettings.topP,
50603
- topK: callSettings.topK,
50604
- presencePenalty: callSettings.presencePenalty,
50605
- frequencyPenalty: callSettings.frequencyPenalty,
50606
- stopSequences: callSettings.stopSequences,
50607
- seed: callSettings.seed,
50608
- maxRetries,
50609
- timeout,
50610
- headers,
50611
- providerOptions,
50612
- stopWhen,
50613
- output,
50614
- abortSignal,
50615
- include,
50616
- functionId: telemetry == null ? undefined : telemetry.functionId,
50617
- metadata: telemetry == null ? undefined : telemetry.metadata,
50618
- experimental_context
50619
- }));
50620
- } catch (_ignored) {}
50621
- const tracer = getTracer(telemetry);
50622
- try {
50623
- return await recordSpan({
50624
- name: "ai.generateText",
50625
- attributes: selectTelemetryAttributes({
50626
- telemetry,
50627
- attributes: {
50628
- ...assembleOperationName({
50629
- operationId: "ai.generateText",
50630
- telemetry
50631
- }),
50632
- ...baseTelemetryAttributes,
50633
- "ai.model.provider": model.provider,
50634
- "ai.model.id": model.modelId,
50635
- "ai.prompt": {
50636
- input: () => JSON.stringify({ system, prompt, messages })
50637
- }
50638
- }
50639
- }),
50640
- tracer,
50641
- fn: async (span) => {
50642
- var _a21, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
50643
- const initialMessages = initialPrompt.messages;
50644
- const responseMessages = [];
50645
- const { approvedToolApprovals, deniedToolApprovals } = collectToolApprovals({ messages: initialMessages });
50646
- const localApprovedToolApprovals = approvedToolApprovals.filter((toolApproval) => !toolApproval.toolCall.providerExecuted);
50647
- if (deniedToolApprovals.length > 0 || localApprovedToolApprovals.length > 0) {
50648
- const toolOutputs = await executeTools({
50649
- toolCalls: localApprovedToolApprovals.map((toolApproval) => toolApproval.toolCall),
50650
- tools,
50651
- tracer,
50652
- telemetry,
50653
- messages: initialMessages,
50654
- abortSignal: mergedAbortSignal,
50655
- experimental_context,
50656
- stepNumber: 0,
50657
- model: modelInfo,
50658
- onToolCallStart,
50659
- onToolCallFinish
50660
- });
50661
- const toolContent = [];
50662
- for (const output2 of toolOutputs) {
50663
- const modelOutput = await createToolModelOutput({
50664
- toolCallId: output2.toolCallId,
50665
- input: output2.input,
50666
- tool: tools == null ? undefined : tools[output2.toolName],
50667
- output: output2.type === "tool-result" ? output2.output : output2.error,
50668
- errorMode: output2.type === "tool-error" ? "json" : "none"
50669
- });
50670
- toolContent.push({
50671
- type: "tool-result",
50672
- toolCallId: output2.toolCallId,
50673
- toolName: output2.toolName,
50674
- output: modelOutput
50675
- });
50676
- }
50677
- for (const toolApproval of deniedToolApprovals) {
50678
- toolContent.push({
50679
- type: "tool-result",
50680
- toolCallId: toolApproval.toolCall.toolCallId,
50681
- toolName: toolApproval.toolCall.toolName,
50682
- output: {
50683
- type: "execution-denied",
50684
- reason: toolApproval.approvalResponse.reason,
50685
- ...toolApproval.toolCall.providerExecuted && {
50686
- providerOptions: {
50687
- openai: {
50688
- approvalId: toolApproval.approvalResponse.approvalId
50689
- }
50690
- }
50691
- }
50692
- }
50693
- });
50694
- }
50695
- responseMessages.push({
50696
- role: "tool",
50697
- content: toolContent
50698
- });
50699
- }
50700
- const providerExecutedToolApprovals = [
50701
- ...approvedToolApprovals,
50702
- ...deniedToolApprovals
50703
- ].filter((toolApproval) => toolApproval.toolCall.providerExecuted);
50704
- if (providerExecutedToolApprovals.length > 0) {
50705
- responseMessages.push({
50706
- role: "tool",
50707
- content: providerExecutedToolApprovals.map((toolApproval) => ({
50708
- type: "tool-approval-response",
50709
- approvalId: toolApproval.approvalResponse.approvalId,
50710
- approved: toolApproval.approvalResponse.approved,
50711
- reason: toolApproval.approvalResponse.reason,
50712
- providerExecuted: true
50713
- }))
50714
- });
50715
- }
50716
- const callSettings2 = prepareCallSettings(settings);
50717
- let currentModelResponse;
50718
- let clientToolCalls = [];
50719
- let clientToolOutputs = [];
50720
- const steps = [];
50721
- const pendingDeferredToolCalls = /* @__PURE__ */ new Map;
50722
- do {
50723
- const stepTimeoutId = stepTimeoutMs != null ? setTimeout(() => stepAbortController.abort(), stepTimeoutMs) : undefined;
50724
- try {
50725
- const stepInputMessages = [...initialMessages, ...responseMessages];
50726
- const prepareStepResult = await (prepareStep == null ? undefined : prepareStep({
50727
- model,
50728
- steps,
50729
- stepNumber: steps.length,
50730
- messages: stepInputMessages,
50731
- experimental_context
50732
- }));
50733
- const stepModel = resolveLanguageModel((_a21 = prepareStepResult == null ? undefined : prepareStepResult.model) != null ? _a21 : model);
50734
- const stepModelInfo = {
50735
- provider: stepModel.provider,
50736
- modelId: stepModel.modelId
50737
- };
50738
- const promptMessages = await convertToLanguageModelPrompt({
50739
- prompt: {
50740
- system: (_b16 = prepareStepResult == null ? undefined : prepareStepResult.system) != null ? _b16 : initialPrompt.system,
50741
- messages: (_c = prepareStepResult == null ? undefined : prepareStepResult.messages) != null ? _c : stepInputMessages
50742
- },
50743
- supportedUrls: await stepModel.supportedUrls,
50744
- download: download2
50745
- });
50746
- experimental_context = (_d = prepareStepResult == null ? undefined : prepareStepResult.experimental_context) != null ? _d : experimental_context;
50747
- const stepActiveTools = (_e = prepareStepResult == null ? undefined : prepareStepResult.activeTools) != null ? _e : activeTools;
50748
- const { toolChoice: stepToolChoice, tools: stepTools } = await prepareToolsAndToolChoice({
50749
- tools,
50750
- toolChoice: (_f = prepareStepResult == null ? undefined : prepareStepResult.toolChoice) != null ? _f : toolChoice,
50751
- activeTools: stepActiveTools
50752
- });
50753
- const stepMessages = (_g = prepareStepResult == null ? undefined : prepareStepResult.messages) != null ? _g : stepInputMessages;
50754
- const stepSystem = (_h = prepareStepResult == null ? undefined : prepareStepResult.system) != null ? _h : initialPrompt.system;
50755
- const stepProviderOptions = mergeObjects(providerOptions, prepareStepResult == null ? undefined : prepareStepResult.providerOptions);
50756
- try {
50757
- await (onStepStart == null ? undefined : onStepStart({
50758
- stepNumber: steps.length,
50759
- model: stepModelInfo,
50760
- system: stepSystem,
50761
- messages: stepMessages,
50762
- tools,
50763
- toolChoice: stepToolChoice,
50764
- activeTools: stepActiveTools,
50765
- steps: [...steps],
50766
- providerOptions: stepProviderOptions,
50767
- timeout,
50768
- headers,
50769
- stopWhen,
50770
- output,
50771
- abortSignal,
50772
- include,
50773
- functionId: telemetry == null ? undefined : telemetry.functionId,
50774
- metadata: telemetry == null ? undefined : telemetry.metadata,
50775
- experimental_context
50776
- }));
50777
- } catch (_ignored) {}
50778
- currentModelResponse = await retry(() => {
50779
- var _a222;
50780
- return recordSpan({
50781
- name: "ai.generateText.doGenerate",
50782
- attributes: selectTelemetryAttributes({
50783
- telemetry,
50784
- attributes: {
50785
- ...assembleOperationName({
50786
- operationId: "ai.generateText.doGenerate",
50787
- telemetry
50788
- }),
50789
- ...baseTelemetryAttributes,
50790
- "ai.model.provider": stepModel.provider,
50791
- "ai.model.id": stepModel.modelId,
50792
- "ai.prompt.messages": {
50793
- input: () => stringifyForTelemetry(promptMessages)
50794
- },
50795
- "ai.prompt.tools": {
50796
- input: () => stepTools == null ? undefined : stepTools.map((tool2) => JSON.stringify(tool2))
50797
- },
50798
- "ai.prompt.toolChoice": {
50799
- input: () => stepToolChoice != null ? JSON.stringify(stepToolChoice) : undefined
50800
- },
50801
- "gen_ai.system": stepModel.provider,
50802
- "gen_ai.request.model": stepModel.modelId,
50803
- "gen_ai.request.frequency_penalty": settings.frequencyPenalty,
50804
- "gen_ai.request.max_tokens": settings.maxOutputTokens,
50805
- "gen_ai.request.presence_penalty": settings.presencePenalty,
50806
- "gen_ai.request.stop_sequences": settings.stopSequences,
50807
- "gen_ai.request.temperature": (_a222 = settings.temperature) != null ? _a222 : undefined,
50808
- "gen_ai.request.top_k": settings.topK,
50809
- "gen_ai.request.top_p": settings.topP
50810
- }
50811
- }),
50812
- tracer,
50813
- fn: async (span2) => {
50814
- var _a232, _b23, _c2, _d2, _e2, _f2, _g2, _h2;
50815
- const result = await stepModel.doGenerate({
50816
- ...callSettings2,
50817
- tools: stepTools,
50818
- toolChoice: stepToolChoice,
50819
- responseFormat: await (output == null ? undefined : output.responseFormat),
50820
- prompt: promptMessages,
50821
- providerOptions: stepProviderOptions,
50822
- abortSignal: mergedAbortSignal,
50823
- headers: headersWithUserAgent
50824
- });
50825
- const responseData = {
50826
- id: (_b23 = (_a232 = result.response) == null ? undefined : _a232.id) != null ? _b23 : generateId2(),
50827
- timestamp: (_d2 = (_c2 = result.response) == null ? undefined : _c2.timestamp) != null ? _d2 : /* @__PURE__ */ new Date,
50828
- modelId: (_f2 = (_e2 = result.response) == null ? undefined : _e2.modelId) != null ? _f2 : stepModel.modelId,
50829
- headers: (_g2 = result.response) == null ? undefined : _g2.headers,
50830
- body: (_h2 = result.response) == null ? undefined : _h2.body
50831
- };
50832
- span2.setAttributes(await selectTelemetryAttributes({
50833
- telemetry,
50834
- attributes: {
50835
- "ai.response.finishReason": result.finishReason.unified,
50836
- "ai.response.text": {
50837
- output: () => extractTextContent(result.content)
50838
- },
50839
- "ai.response.reasoning": {
50840
- output: () => extractReasoningContent(result.content)
50841
- },
50842
- "ai.response.toolCalls": {
50843
- output: () => {
50844
- const toolCalls = asToolCalls(result.content);
50845
- return toolCalls == null ? undefined : JSON.stringify(toolCalls);
50846
- }
50847
- },
50848
- "ai.response.id": responseData.id,
50849
- "ai.response.model": responseData.modelId,
50850
- "ai.response.timestamp": responseData.timestamp.toISOString(),
50851
- "ai.response.providerMetadata": JSON.stringify(result.providerMetadata),
50852
- "ai.usage.promptTokens": result.usage.inputTokens.total,
50853
- "ai.usage.completionTokens": result.usage.outputTokens.total,
50854
- "gen_ai.response.finish_reasons": [
50855
- result.finishReason.unified
50856
- ],
50857
- "gen_ai.response.id": responseData.id,
50858
- "gen_ai.response.model": responseData.modelId,
50859
- "gen_ai.usage.input_tokens": result.usage.inputTokens.total,
50860
- "gen_ai.usage.output_tokens": result.usage.outputTokens.total
50861
- }
50862
- }));
50863
- return { ...result, response: responseData };
50864
- }
50865
- });
50866
- });
50867
- const stepToolCalls = await Promise.all(currentModelResponse.content.filter((part) => part.type === "tool-call").map((toolCall) => parseToolCall({
50868
- toolCall,
50869
- tools,
50870
- repairToolCall,
50871
- system,
50872
- messages: stepInputMessages
50873
- })));
50874
- const toolApprovalRequests = {};
50875
- for (const toolCall of stepToolCalls) {
50876
- if (toolCall.invalid) {
50877
- continue;
50878
- }
50879
- const tool2 = tools == null ? undefined : tools[toolCall.toolName];
50880
- if (tool2 == null) {
50881
- continue;
50882
- }
50883
- if ((tool2 == null ? undefined : tool2.onInputAvailable) != null) {
50884
- await tool2.onInputAvailable({
50885
- input: toolCall.input,
50886
- toolCallId: toolCall.toolCallId,
50887
- messages: stepInputMessages,
50888
- abortSignal: mergedAbortSignal,
50889
- experimental_context
50890
- });
50891
- }
50892
- if (await isApprovalNeeded({
50893
- tool: tool2,
50894
- toolCall,
50895
- messages: stepInputMessages,
50896
- experimental_context
50897
- })) {
50898
- toolApprovalRequests[toolCall.toolCallId] = {
50899
- type: "tool-approval-request",
50900
- approvalId: generateId2(),
50901
- toolCall
50902
- };
50903
- }
50904
- }
50905
- const invalidToolCalls = stepToolCalls.filter((toolCall) => toolCall.invalid && toolCall.dynamic);
50906
- clientToolOutputs = [];
50907
- for (const toolCall of invalidToolCalls) {
50908
- clientToolOutputs.push({
50909
- type: "tool-error",
50910
- toolCallId: toolCall.toolCallId,
50911
- toolName: toolCall.toolName,
50912
- input: toolCall.input,
50913
- error: getErrorMessage2(toolCall.error),
50914
- dynamic: true
50915
- });
50916
- }
50917
- clientToolCalls = stepToolCalls.filter((toolCall) => !toolCall.providerExecuted);
50918
- if (tools != null) {
50919
- clientToolOutputs.push(...await executeTools({
50920
- toolCalls: clientToolCalls.filter((toolCall) => !toolCall.invalid && toolApprovalRequests[toolCall.toolCallId] == null),
50921
- tools,
50922
- tracer,
50923
- telemetry,
50924
- messages: stepInputMessages,
50925
- abortSignal: mergedAbortSignal,
50926
- experimental_context,
50927
- stepNumber: steps.length,
50928
- model: stepModelInfo,
50929
- onToolCallStart,
50930
- onToolCallFinish
50931
- }));
50932
- }
50933
- for (const toolCall of stepToolCalls) {
50934
- if (!toolCall.providerExecuted)
50935
- continue;
50936
- const tool2 = tools == null ? undefined : tools[toolCall.toolName];
50937
- if ((tool2 == null ? undefined : tool2.type) === "provider" && tool2.supportsDeferredResults) {
50938
- const hasResultInResponse = currentModelResponse.content.some((part) => part.type === "tool-result" && part.toolCallId === toolCall.toolCallId);
50939
- if (!hasResultInResponse) {
50940
- pendingDeferredToolCalls.set(toolCall.toolCallId, {
50941
- toolName: toolCall.toolName
50942
- });
50943
- }
50944
- }
50945
- }
50946
- for (const part of currentModelResponse.content) {
50947
- if (part.type === "tool-result") {
50948
- pendingDeferredToolCalls.delete(part.toolCallId);
50949
- }
50950
- }
50951
- const stepContent = asContent({
50952
- content: currentModelResponse.content,
50953
- toolCalls: stepToolCalls,
50954
- toolOutputs: clientToolOutputs,
50955
- toolApprovalRequests: Object.values(toolApprovalRequests),
50956
- tools
50957
- });
50958
- responseMessages.push(...await toResponseMessages({
50959
- content: stepContent,
50960
- tools
50961
- }));
50962
- const stepRequest = ((_i = include == null ? undefined : include.requestBody) != null ? _i : true) ? (_j = currentModelResponse.request) != null ? _j : {} : { ...currentModelResponse.request, body: undefined };
50963
- const stepResponse = {
50964
- ...currentModelResponse.response,
50965
- messages: structuredClone(responseMessages),
50966
- body: ((_k = include == null ? undefined : include.responseBody) != null ? _k : true) ? (_l = currentModelResponse.response) == null ? undefined : _l.body : undefined
50967
- };
50968
- const stepNumber = steps.length;
50969
- const currentStepResult = new DefaultStepResult({
50970
- stepNumber,
50971
- model: stepModelInfo,
50972
- functionId: telemetry == null ? undefined : telemetry.functionId,
50973
- metadata: telemetry == null ? undefined : telemetry.metadata,
50974
- experimental_context,
50975
- content: stepContent,
50976
- finishReason: currentModelResponse.finishReason.unified,
50977
- rawFinishReason: currentModelResponse.finishReason.raw,
50978
- usage: asLanguageModelUsage(currentModelResponse.usage),
50979
- warnings: currentModelResponse.warnings,
50980
- providerMetadata: currentModelResponse.providerMetadata,
50981
- request: stepRequest,
50982
- response: stepResponse
50983
- });
50984
- logWarnings({
50985
- warnings: (_m = currentModelResponse.warnings) != null ? _m : [],
50986
- provider: stepModelInfo.provider,
50987
- model: stepModelInfo.modelId
50988
- });
50989
- steps.push(currentStepResult);
50990
- await (onStepFinish == null ? undefined : onStepFinish(currentStepResult));
50991
- } finally {
50992
- if (stepTimeoutId != null) {
50993
- clearTimeout(stepTimeoutId);
50994
- }
50995
- }
50996
- } while ((clientToolCalls.length > 0 && clientToolOutputs.length === clientToolCalls.length || pendingDeferredToolCalls.size > 0) && !await isStopConditionMet({ stopConditions, steps }));
50997
- span.setAttributes(await selectTelemetryAttributes({
50998
- telemetry,
50999
- attributes: {
51000
- "ai.response.finishReason": currentModelResponse.finishReason.unified,
51001
- "ai.response.text": {
51002
- output: () => extractTextContent(currentModelResponse.content)
51003
- },
51004
- "ai.response.reasoning": {
51005
- output: () => extractReasoningContent(currentModelResponse.content)
51006
- },
51007
- "ai.response.toolCalls": {
51008
- output: () => {
51009
- const toolCalls = asToolCalls(currentModelResponse.content);
51010
- return toolCalls == null ? undefined : JSON.stringify(toolCalls);
51011
- }
51012
- },
51013
- "ai.response.providerMetadata": JSON.stringify(currentModelResponse.providerMetadata),
51014
- "ai.usage.promptTokens": currentModelResponse.usage.inputTokens.total,
51015
- "ai.usage.completionTokens": currentModelResponse.usage.outputTokens.total
51016
- }
51017
- }));
51018
- const lastStep = steps[steps.length - 1];
51019
- const totalUsage = steps.reduce((totalUsage2, step) => {
51020
- return addLanguageModelUsage(totalUsage2, step.usage);
51021
- }, {
51022
- inputTokens: undefined,
51023
- outputTokens: undefined,
51024
- totalTokens: undefined,
51025
- reasoningTokens: undefined,
51026
- cachedInputTokens: undefined
51027
- });
51028
- await (onFinish == null ? undefined : onFinish({
51029
- stepNumber: lastStep.stepNumber,
51030
- model: lastStep.model,
51031
- functionId: lastStep.functionId,
51032
- metadata: lastStep.metadata,
51033
- experimental_context: lastStep.experimental_context,
51034
- finishReason: lastStep.finishReason,
51035
- rawFinishReason: lastStep.rawFinishReason,
51036
- usage: lastStep.usage,
51037
- content: lastStep.content,
51038
- text: lastStep.text,
51039
- reasoningText: lastStep.reasoningText,
51040
- reasoning: lastStep.reasoning,
51041
- files: lastStep.files,
51042
- sources: lastStep.sources,
51043
- toolCalls: lastStep.toolCalls,
51044
- staticToolCalls: lastStep.staticToolCalls,
51045
- dynamicToolCalls: lastStep.dynamicToolCalls,
51046
- toolResults: lastStep.toolResults,
51047
- staticToolResults: lastStep.staticToolResults,
51048
- dynamicToolResults: lastStep.dynamicToolResults,
51049
- request: lastStep.request,
51050
- response: lastStep.response,
51051
- warnings: lastStep.warnings,
51052
- providerMetadata: lastStep.providerMetadata,
51053
- steps,
51054
- totalUsage
51055
- }));
51056
- let resolvedOutput;
51057
- if (lastStep.finishReason === "stop") {
51058
- const outputSpecification = output != null ? output : text();
51059
- resolvedOutput = await outputSpecification.parseCompleteOutput({ text: lastStep.text }, {
51060
- response: lastStep.response,
51061
- usage: lastStep.usage,
51062
- finishReason: lastStep.finishReason
51063
- });
51064
- }
51065
- return new DefaultGenerateTextResult({
51066
- steps,
51067
- totalUsage,
51068
- output: resolvedOutput
51069
- });
51070
- }
51071
- });
51072
- } catch (error48) {
51073
- throw wrapGatewayError(error48);
51074
- }
51075
- }
51076
- async function executeTools({
51077
- toolCalls,
51078
- tools,
51079
- tracer,
51080
- telemetry,
51081
- messages,
51082
- abortSignal,
51083
- experimental_context,
51084
- stepNumber,
51085
- model,
51086
- onToolCallStart,
51087
- onToolCallFinish
51088
- }) {
51089
- const toolOutputs = await Promise.all(toolCalls.map(async (toolCall) => executeToolCall({
51090
- toolCall,
51091
- tools,
51092
- tracer,
51093
- telemetry,
51094
- messages,
51095
- abortSignal,
51096
- experimental_context,
51097
- stepNumber,
51098
- model,
51099
- onToolCallStart,
51100
- onToolCallFinish
51101
- })));
51102
- return toolOutputs.filter((output) => output != null);
51103
- }
51104
- var DefaultGenerateTextResult = class {
51105
- constructor(options) {
51106
- this.steps = options.steps;
51107
- this._output = options.output;
51108
- this.totalUsage = options.totalUsage;
51109
- }
51110
- get finalStep() {
51111
- return this.steps[this.steps.length - 1];
51112
- }
51113
- get content() {
51114
- return this.finalStep.content;
51115
- }
51116
- get text() {
51117
- return this.finalStep.text;
51118
- }
51119
- get files() {
51120
- return this.finalStep.files;
51121
- }
51122
- get reasoningText() {
51123
- return this.finalStep.reasoningText;
51124
- }
51125
- get reasoning() {
51126
- return this.finalStep.reasoning;
51127
- }
51128
- get toolCalls() {
51129
- return this.finalStep.toolCalls;
51130
- }
51131
- get staticToolCalls() {
51132
- return this.finalStep.staticToolCalls;
51133
- }
51134
- get dynamicToolCalls() {
51135
- return this.finalStep.dynamicToolCalls;
51136
- }
51137
- get toolResults() {
51138
- return this.finalStep.toolResults;
51139
- }
51140
- get staticToolResults() {
51141
- return this.finalStep.staticToolResults;
51142
- }
51143
- get dynamicToolResults() {
51144
- return this.finalStep.dynamicToolResults;
51145
- }
51146
- get sources() {
51147
- return this.finalStep.sources;
51148
- }
51149
- get finishReason() {
51150
- return this.finalStep.finishReason;
51151
- }
51152
- get rawFinishReason() {
51153
- return this.finalStep.rawFinishReason;
51154
- }
51155
- get warnings() {
51156
- return this.finalStep.warnings;
51157
- }
51158
- get providerMetadata() {
51159
- return this.finalStep.providerMetadata;
51160
- }
51161
- get response() {
51162
- return this.finalStep.response;
51163
- }
51164
- get request() {
51165
- return this.finalStep.request;
51166
- }
51167
- get usage() {
51168
- return this.finalStep.usage;
51169
- }
51170
- get experimental_output() {
51171
- return this.output;
51172
- }
51173
- get output() {
51174
- if (this._output == null) {
51175
- throw new NoOutputGeneratedError;
51176
- }
51177
- return this._output;
51178
- }
51179
- };
51180
- function asToolCalls(content) {
51181
- const parts = content.filter((part) => part.type === "tool-call");
51182
- if (parts.length === 0) {
51183
- return;
51184
- }
51185
- return parts.map((toolCall) => ({
51186
- toolCallId: toolCall.toolCallId,
51187
- toolName: toolCall.toolName,
51188
- input: toolCall.input
51189
- }));
51190
- }
51191
- function asContent({
51192
- content,
51193
- toolCalls,
51194
- toolOutputs,
51195
- toolApprovalRequests,
51196
- tools
51197
- }) {
51198
- const contentParts = [];
51199
- for (const part of content) {
51200
- switch (part.type) {
51201
- case "text":
51202
- case "reasoning":
51203
- case "source":
51204
- contentParts.push(part);
51205
- break;
51206
- case "file": {
51207
- contentParts.push({
51208
- type: "file",
51209
- file: new DefaultGeneratedFile(part),
51210
- ...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
51211
- });
51212
- break;
51213
- }
51214
- case "tool-call": {
51215
- contentParts.push(toolCalls.find((toolCall) => toolCall.toolCallId === part.toolCallId));
51216
- break;
51217
- }
51218
- case "tool-result": {
51219
- const toolCall = toolCalls.find((toolCall2) => toolCall2.toolCallId === part.toolCallId);
51220
- if (toolCall == null) {
51221
- const tool2 = tools == null ? undefined : tools[part.toolName];
51222
- const supportsDeferredResults = (tool2 == null ? undefined : tool2.type) === "provider" && tool2.supportsDeferredResults;
51223
- if (!supportsDeferredResults) {
51224
- throw new Error(`Tool call ${part.toolCallId} not found.`);
51225
- }
51226
- if (part.isError) {
51227
- contentParts.push({
51228
- type: "tool-error",
51229
- toolCallId: part.toolCallId,
51230
- toolName: part.toolName,
51231
- input: undefined,
51232
- error: part.result,
51233
- providerExecuted: true,
51234
- dynamic: part.dynamic
51235
- });
51236
- } else {
51237
- contentParts.push({
51238
- type: "tool-result",
51239
- toolCallId: part.toolCallId,
51240
- toolName: part.toolName,
51241
- input: undefined,
51242
- output: part.result,
51243
- providerExecuted: true,
51244
- dynamic: part.dynamic
51245
- });
51246
- }
51247
- break;
51248
- }
51249
- if (part.isError) {
51250
- contentParts.push({
51251
- type: "tool-error",
51252
- toolCallId: part.toolCallId,
51253
- toolName: part.toolName,
51254
- input: toolCall.input,
51255
- error: part.result,
51256
- providerExecuted: true,
51257
- dynamic: toolCall.dynamic
51258
- });
51259
- } else {
51260
- contentParts.push({
51261
- type: "tool-result",
51262
- toolCallId: part.toolCallId,
51263
- toolName: part.toolName,
51264
- input: toolCall.input,
51265
- output: part.result,
51266
- providerExecuted: true,
51267
- dynamic: toolCall.dynamic
51268
- });
51269
- }
51270
- break;
51271
- }
51272
- case "tool-approval-request": {
51273
- const toolCall = toolCalls.find((toolCall2) => toolCall2.toolCallId === part.toolCallId);
51274
- if (toolCall == null) {
51275
- throw new ToolCallNotFoundForApprovalError({
51276
- toolCallId: part.toolCallId,
51277
- approvalId: part.approvalId
51278
- });
51279
- }
51280
- contentParts.push({
51281
- type: "tool-approval-request",
51282
- approvalId: part.approvalId,
51283
- toolCall
51284
- });
51285
- break;
51286
- }
51287
- }
51288
- }
51289
- return [...contentParts, ...toolOutputs, ...toolApprovalRequests];
51290
- }
51291
50545
  function prepareHeaders(headers, defaultHeaders) {
51292
50546
  const responseHeaders = new Headers(headers != null ? headers : {});
51293
50547
  for (const [key, value] of Object.entries(defaultHeaders)) {
@@ -54441,43 +53695,29 @@ var defaultDownload2 = createDownload();
54441
53695
 
54442
53696
  // src/run.ts
54443
53697
  async function runQuery(options) {
54444
- const { model, query, systemPrompt, stream } = options;
53698
+ const { model, query, systemPrompt } = options;
54445
53699
  try {
54446
- if (stream) {
54447
- return await runStreamingQuery(model, query, systemPrompt);
53700
+ const result = streamText({
53701
+ model,
53702
+ system: systemPrompt,
53703
+ prompt: query
53704
+ });
53705
+ let fullText = "";
53706
+ for await (const textPart of result.textStream) {
53707
+ process.stdout.write(textPart);
53708
+ fullText += textPart;
53709
+ }
53710
+ if (!fullText.endsWith(`
53711
+ `)) {
53712
+ process.stdout.write(`
53713
+ `);
54448
53714
  }
54449
- return await runNonStreamingQuery(model, query, systemPrompt);
53715
+ return { text: fullText };
54450
53716
  } catch (err) {
54451
53717
  const message = err instanceof Error ? err.message : String(err);
54452
53718
  throw new ProviderError(`AI request failed: ${message}`);
54453
53719
  }
54454
53720
  }
54455
- async function runNonStreamingQuery(model, query, systemPrompt) {
54456
- const result = await generateText({
54457
- model,
54458
- system: systemPrompt,
54459
- prompt: query
54460
- });
54461
- return { text: result.text };
54462
- }
54463
- async function runStreamingQuery(model, query, systemPrompt) {
54464
- const result = streamText({
54465
- model,
54466
- system: systemPrompt,
54467
- prompt: query
54468
- });
54469
- let fullText = "";
54470
- for await (const textPart of result.textStream) {
54471
- process.stdout.write(textPart);
54472
- fullText += textPart;
54473
- }
54474
- if (!fullText.endsWith(`
54475
- `)) {
54476
- process.stdout.write(`
54477
- `);
54478
- }
54479
- return { text: fullText };
54480
- }
54481
53721
 
54482
53722
  // src/cli.ts
54483
53723
  async function main() {
@@ -54509,39 +53749,24 @@ async function main() {
54509
53749
  console.log(listProviders(config3));
54510
53750
  process.exit(0);
54511
53751
  }
53752
+ const query = args.query.join(" ");
53753
+ const MAX_QUERY_LENGTH = 5000;
53754
+ if (query.length > MAX_QUERY_LENGTH) {
53755
+ throw new UsageError2(`Query too long (${query.length} characters). Maximum is ${MAX_QUERY_LENGTH}.`);
53756
+ }
54512
53757
  logDebug2("Loading config...", debug);
54513
53758
  const config2 = await loadConfig();
54514
53759
  logDebug2(`Resolving provider: ${args.options.provider ?? config2.default.provider}`, debug);
54515
53760
  const { model, providerName, modelId } = resolveProvider(config2, args.options.provider, args.options.model, debug);
54516
- const query = args.query.join(" ");
54517
53761
  const envInfo = getEnvironmentInfo();
54518
53762
  logDebug2(`Query: ${query}`, debug);
54519
53763
  logDebug2(`Provider: ${providerName}, Model: ${modelId}`, debug);
54520
- logDebug2(`Stream: ${args.options.stream}`, debug);
54521
53764
  logDebug2(formatEnvForDebug(envInfo), debug);
54522
53765
  const result = await runQuery({
54523
53766
  model,
54524
53767
  query,
54525
- systemPrompt: buildSystemPrompt(envInfo),
54526
- stream: args.options.stream
54527
- });
54528
- if (!args.options.stream) {
54529
- const output = formatOutput({
54530
- text: result.text,
54531
- providerName,
54532
- modelId,
54533
- json: args.options.json
54534
- });
54535
- console.log(output);
54536
- } else if (args.options.json) {
54537
- const output = formatOutput({
54538
- text: result.text,
54539
- providerName,
54540
- modelId,
54541
- json: true
54542
- });
54543
- console.log(output);
54544
- }
53768
+ systemPrompt: buildSystemPrompt(envInfo)
53769
+ });
54545
53770
  if (args.options.copy) {
54546
53771
  await clipboardy_default.write(result.text);
54547
53772
  logDebug2("Copied to clipboard", debug);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hongymagic/q",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Quick AI answers from the command line",
5
5
  "main": "dist/q.js",
6
6
  "type": "module",