Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
31 changes: 10 additions & 21 deletions apps/desktop/src/renderer/src/hooks/agent-event-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,15 @@ export function applyAgentEvent(
if (existingMsg) {
// Already exists, mark as not finished
return prev.map(m =>
m.id === event.reply_id ? { ...m, finished_at: undefined } : m
m.id === event.reply_id ? { ...m, finished_at: null } : m
);
}
const newMsg: Msg = {
...createMsg({
id: event.reply_id,
role: event.role,
name: event.name,
content: [],
}),
finished_at: undefined,
};
const newMsg = createMsg({
id: event.reply_id,
role: event.role,
name: event.name,
content: [],
});
return [...prev, newMsg];
});
break;
Expand All @@ -58,17 +55,9 @@ export function applyAgentEvent(
setMessages(prev =>
prev.map(m => {
if (m.id !== event.reply_id) return m;
const currentUsage = m.usage || {
input_tokens: 0,
output_tokens: 0,
};
return {
...m,
usage: {
input_tokens: currentUsage.input_tokens + event.input_tokens,
output_tokens: currentUsage.output_tokens + event.output_tokens,
},
};
const cloned: Msg = { ...m, content: m.content.map(b => ({ ...b })) };
Comment thread
DavdGao marked this conversation as resolved.
appendEvent(cloned, event);
return cloned;
})
);
break;
Expand Down
16 changes: 16 additions & 0 deletions packages/agentscope/src/_utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ import { jsonrepair } from 'jsonrepair';

import { JSONSerializableObject } from '../type';

/**
* Generate a Python-compatible entity identifier.
* @returns A UUID hex string.
*/
export function _generateId(): string {
return crypto.randomUUID().replaceAll('-', '');
}

/**
* Generate an ISO-8601 entity timestamp.
* @returns The current timestamp.
*/
export function _generateTimestamp(): string {
return new Date().toISOString();
}

/**
* Decode a base64 string to a Uint8Array.
* Works in both Node.js and browser environments.
Expand Down
11 changes: 10 additions & 1 deletion packages/agentscope/src/agent/agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ describe('Human-in-the-loop', () => {
name: 'Friday',
role: 'assistant',
created_at: expect.any(String),
usage: null,
finished_at: null,
finished_reason: null,
structured_output: null,
error: null,
},
]);

Expand Down Expand Up @@ -408,7 +413,11 @@ describe('Human-in-the-loop', () => {
name: 'Friday',
role: 'assistant',
created_at: expect.any(String),
finished_at: undefined,
usage: null,
finished_at: null,
finished_reason: null,
structured_output: null,
error: null,
},
]);

Expand Down
11 changes: 9 additions & 2 deletions packages/agentscope/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,13 @@ export class Agent {
*/
protected _saveToContext(blocks: ContentBlock[], usage?: ChatUsage): void {
const msgUsage: Msg['usage'] = usage
? { input_tokens: usage.inputTokens, output_tokens: usage.outputTokens }
: undefined;
? {
input_tokens: usage.inputTokens,
output_tokens: usage.outputTokens,
cache_input_tokens: 0,
cache_creation_input_tokens: 0,
}
: null;
const lastMsg = this.context.at(-1);
if (this.context.length === 0) {
this.context.push(
Expand All @@ -282,6 +287,8 @@ export class Agent {
lastMsg.usage = {
input_tokens: 0,
output_tokens: 0,
cache_input_tokens: 0,
cache_creation_input_tokens: 0,
};
}
lastMsg.usage.input_tokens = lastMsg.usage.input_tokens + msgUsage.input_tokens;
Expand Down
47 changes: 6 additions & 41 deletions packages/agentscope/src/event/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { DataBlock, TextBlock, ToolCallBlock, ToolResultBlock } from '../message';
import { PermissionRule } from '../permission';
import { ErrorInfo, ReplyFinishedReason } from '../type';

export { ErrorType, ReplyFinishedReason } from '../type';
export type { ErrorInfo } from '../type';

export enum EventType {
REPLY_START = 'REPLY_START',
Expand Down Expand Up @@ -56,47 +60,6 @@ export interface ReplyStartEvent extends EventBase {
role: 'user' | 'assistant' | 'system';
}

/** The reason a reply finished. */
export enum ReplyFinishedReason {
COMPLETED = 'completed',
INTERRUPTED = 'interrupted',
EXCEED_MAX_ITERS = 'exceed_max_iters',
ERROR = 'error',
}

/**
* Classification of a fatal error that terminated a reply.
*
* Not model-specific: the status-derived members apply to any upstream
* service reached during a reply (chat model, embedding, TTS, MCP).
*/
export enum ErrorType {
/** 401 — credential missing or wrong. */
AUTHENTICATION = 'authentication',
/** 403 — authenticated but not allowed. */
PERMISSION = 'permission',
/** 429 — rate/quota exceeded. */
RATE_LIMIT = 'rate_limit',
/** 400 / 422 — malformed request. */
INVALID_REQUEST = 'invalid_request',
/** 5xx — an upstream service failed. */
UPSTREAM = 'upstream',
/** Network error / timeout — no HTTP status available. */
CONNECTION = 'connection',
/** Framework bug or otherwise unexpected exception. */
INTERNAL = 'internal',
/** Fallback when no better classification is possible. */
UNKNOWN = 'unknown',
}

/** Structured, UI-facing description of a fatal reply error. */
export interface ErrorInfo {
/** Stable classification key; the frontend localizes off it. */
type: ErrorType;
/** Short, sanitized, human-readable description. */
message: string;
}

export interface ReplyEndEvent extends EventBase {
type: EventType.REPLY_END;
session_id: string;
Expand All @@ -121,6 +84,8 @@ export interface ModelCallEndEvent extends EventBase {
reply_id: string;
input_tokens: number;
output_tokens: number;
cache_input_tokens?: number;
cache_creation_input_tokens?: number;
}

export interface TextBlockStartEvent extends EventBase {
Expand Down
Loading
Loading