Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { uiEventRecorder } from '../../../amazonq/util/eventRecorder'
import { globals } from '../../../shared'
import { telemetry } from '../../../shared/telemetry'
import { isSsoConnection } from '../../../auth/connection'
import { formatObj } from '../../../shared/utilities/collectionUtils'

export interface ChatControllerMessagePublishers {
readonly processPromptChatMessage: MessagePublisher<PromptMessage>
Expand Down Expand Up @@ -650,7 +651,9 @@ export class ChatController {

const request = triggerPayloadToChatRequest(triggerPayload)
const session = this.sessionStorage.getSession(tabID)
getLogger().info(`request from tab: ${tabID} conversationID: ${session.sessionIdentifier} request: %O`, request)
getLogger().info(
`request from tab: ${tabID} conversationID: ${session.sessionIdentifier} request: ${formatObj(request, { depth: 12 })}`
)
let response: MessengerResponseType | undefined = undefined
session.createNewTokenSource()
try {
Expand All @@ -675,8 +678,7 @@ export class ChatController {
getLogger().info(
`response to tab: ${tabID} conversationID: ${session.sessionIdentifier} requestID: ${
response.$metadata.requestId
} metadata: %O`,
response.$metadata
} metadata: ${formatObj(response.$metadata, { depth: 12 })}`
)
await this.messenger.sendAIResponse(response, session, tabID, triggerID, triggerPayload)
} catch (e: any) {
Expand Down
30 changes: 29 additions & 1 deletion packages/core/src/shared/utilities/collectionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { isWeb } from '../extensionGlobals'
import { inspect as nodeInspect } from 'util'
import { AsyncCollection, toCollection } from './asyncCollection'
import { SharedProp, AccumulableKeys, Coalesce, isNonNullable } from './tsUtils'

Expand Down Expand Up @@ -297,7 +299,6 @@ export function assign<T extends Record<any, any>, U extends Partial<T>>(data: T
* - depth=2 returns `obj` with its children and their children.
* - and so on...
*
* TODO: node's `util.inspect()` function is better, but doesn't work in web browser?
*
* @param obj Object to clone.
* @param depth
Expand Down Expand Up @@ -329,6 +330,33 @@ export function partialClone(obj: any, depth: number = 3, omitKeys: string[] = [
return clonedObj
}

type inspectOptions = Partial<{
depth: number
omitKeys: string[]
replacement: any
showHidden: boolean
color: boolean
}>

/**
* Wrapper around nodes inspect function that works on web. Defaults to JSON.stringify on web.
* @param obj object to show
* @param opt options for showing (ex. depth, omitting keys)
*/
export function formatObj(obj: any, opt?: inspectOptions): string {
const options = {
depth: opt?.depth ?? 3,
omitKeys: opt?.omitKeys ?? [],
replacement: opt?.replacement,
showHidden: opt?.showHidden ?? false,
color: opt?.color ?? false,
}
const objToShow = partialClone(obj, options.depth, options.omitKeys, options.replacement)
Copy link
Contributor

@justinmk3 justinmk3 Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we skip the partialClone for the non-web case?

I think inspect() probably doesn't need to support partiaClone features (such as omitKeys) Because it's trivial for any caller to use inspect(partialClone(...)).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was worried that some of the options would then only apply in certain cases. Ex. if not on web and we pass omitKeys, it does nothing w/o error or warning. But I guess the caller can just wrap it themselves.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ex. if not on web and we pass omitKeys,

inspect() doesn't really need to support omitKeys though. Unless that is a feature of nodejs inspect().

return isWeb()
? JSON.stringify(objToShow)
: nodeInspect(objToShow, options.showHidden, options.depth, options.color)
}

/** Recursively delete undefined key/value pairs */
export function stripUndefined<T extends Record<string, any>>(
obj: T
Expand Down
39 changes: 37 additions & 2 deletions packages/core/src/test/shared/utilities/collectionUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
joinAll,
isPresent,
partialClone,
formatObj,
} from '../../../shared/utilities/collectionUtils'

import { asyncGenerator } from '../../../shared/utilities/collectionUtils'
Expand Down Expand Up @@ -511,7 +512,7 @@ describe('CollectionUtils', async function () {
const requester = async (request: { next?: string }) => pages[request.next ?? 'page1']

it('creates a new AsyncCollection', async function () {
const collection = pageableToCollection(requester, {}, 'next', 'data')
const collection = pageableToCollection(requester, {}, 'next' as never, 'data')
assert.deepStrictEqual(await collection.promise(), [[0, 1, 2], [3, 4], [5], []])
})

Expand Down Expand Up @@ -540,7 +541,7 @@ describe('CollectionUtils', async function () {

describe('last', function () {
it('it persists last element when mapped', async function () {
const collection = pageableToCollection(requester, {}, 'next', 'data')
const collection = pageableToCollection(requester, {}, 'next' as never, 'data')
const mapped = collection.map((i) => i[0] ?? -1)
assert.strictEqual(await last(mapped), -1)
})
Expand Down Expand Up @@ -679,6 +680,40 @@ describe('CollectionUtils', async function () {
})
})

describe('inspect', function () {
let testData: any
before(function () {
testData = {
root: {
A: {
B: {
C: {
D: {
E: 'data',
},
},
},
},
},
}
})

it('defaults to a depth of 3', function () {
assert.strictEqual(formatObj(testData), '{ root: { A: { B: {} } } }')
})

it('allows depth to be set manually', function () {
assert.strictEqual(
formatObj(testData, { depth: 6 }),
"{\n root: {\n A: {\n B: { C: { D: { E: 'data' } } }\n }\n }\n}"
)
})

it('omits keys specified', function () {
assert.strictEqual(formatObj(testData, { omitKeys: ['D', 'C'] }), '{ root: { A: { B: {} } } }')
})
})

describe('partialClone', function () {
it('omits properties by depth', function () {
const testObj = {
Expand Down
Loading